modify code

master
algorithmzuo 2 years ago
parent df62aeb1fd
commit 0e843ed49b

@ -0,0 +1,107 @@
package class_2022_10_2_week;
import java.util.HashMap;
// 来自小红书
// 小A认为如果在数组中有一个数出现了至少k次
// 且这个数是该数组的众数,即出现次数最多的数之一
// 那么这个数组被该数所支配
// 显然当k比较大的时候有些数组不被任何数所支配
// 现在小A拥有一个长度为n的数组她想知道内部有多少个区间是被某个数支配的
// 2 <= k <= n <= 100000
// 1 <= 数组的值 <= n
public class Code01_RangesHasDominateNumber {
// 暴力方法
// 为了验证
// 时间复杂度O(N^3)
public static int dominates1(int[] arr, int k) {
int n = arr.length;
int ans = 0;
for (int l = 0; l < n; l++) {
for (int r = l; r < n; r++) {
if (ok(arr, l, r, k)) {
ans++;
}
}
}
return ans;
}
public static boolean ok(int[] arr, int l, int r, int k) {
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for (int i = l; i <= r; i++) {
map.put(arr[i], map.getOrDefault(arr[i], 0) + 1);
}
for (int times : map.values()) {
if (times >= k) {
return true;
}
}
return false;
}
// 正式方法
// 时间复杂度O(N)
public static int dominates2(int[] arr, int k) {
int n = arr.length;
// 总数量
int all = n * (n + 1) / 2;
// 不被支配的区间数量
int except = 0;
// 次数表
// 0 : 0
// 1 : 0
// 2 : 0
int[] cnt = new int[n + 1];
// l ... r
// 窗口用这个形式[l,r)
// l...r-1 r(x)
// l == 0 r == 0 [l,r) 一个数也没有
// l == 0 r == 1 [0..0]
for (int l = 0, r = 0; l < n; l++) {
// [r] 即将要进来的
// cnt[arr[r]] + 1 < k
while (r < n && cnt[arr[r]] + 1 < k) {
// cnt[arr[r]]++;
// r++
cnt[arr[r++]]++;
}
// l..l
// l..l+1
// l..l+2
// l..r-1
except += r - l;
cnt[arr[l]]--;
}
return all - except;
}
// 为了测试
public static int[] randomArray(int n) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * n) + 1;
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 100;
int testTimes = 5000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int[] arr = randomArray(n);
int k = (int) (Math.random() * n) + 1;
int ans1 = dominates1(arr, k);
int ans2 = dominates2(arr, k);
if (ans1 != ans2) {
System.out.println("出错了!");
}
}
System.out.println("测试结束");
}
}

@ -0,0 +1,215 @@
package class_2022_10_2_week;
import java.util.Arrays;
// 来自京东
// 实习岗位笔试题
// 给定一个数组arr长度为n
// 任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的!
// 求所有可能的合法子序列中,最大中位数是多少
// 中位数的定义为上中位数
// [1, 2, 3, 4]的上中位数是2
// [1, 2, 3, 4, 5]的上中位数是3
// 2 <= n <= 10^5
// 1 <= arr[i] <= 10^9
// 我写的帖子解答 : https://www.mashibing.com/question/detail/34771
public class Code02_BestMedianPickAdjacent {
public static int validSubMaxSum(int[] arr) {
return zuo(arr, 0, 1);
}
// 当前来到i位置
// 如果arr[i-1]位置的数选了pre == 1
// 如果arr[i-1]位置的数没选pre == 0
// arr[i....]最大合法子序列的累加和是多少
public static int zuo(int[] arr, int i, int pre) {
if (i == arr.length) {
return 0;
}
// 还有数!
// 可能性1 : 不要i位置的数
int p1 = Integer.MIN_VALUE;
if (pre == 1) {
p1 = zuo(arr, i + 1, 0);
}
// 可能性2 : 要i位置的数
int p2 = Integer.MIN_VALUE;
int next2 = zuo(arr, i + 1, 1);
if (next2 != Integer.MIN_VALUE) {
p2 = arr[i] + next2;
}
return Math.max(p1, p2);
}
// 启发函数
// 如果数组中的值只有1和-1
// 你可以从左往右选择数字组成子序列,
// 但是要求任何两个相邻的数至少要选1个
// 请返回子序列的最大累加和
// arr : 数组
// i : 当前来到i位置
// pre : 前一个数字(i-1位置),当初选了没有
// 如果pre == 0, 表示i-1位置的数字当初没有选
// 如果pre == 1, 表示i-1位置的数字当初选了
// 返回arr[i...]的子序列,最大累加和
public static int maxSum(int[] arr, int i, int pre) {
if (i == arr.length) {
return 0;
}
// 可能性1 : 就是要选当前i位置的数
int p1 = arr[i] + maxSum(arr, i + 1, 1);
// 可能性1 : 就是不选当前i位置的数
int p2 = -1;
if (pre == 1) { // 只有前一个数字选了,当前才能不选
p2 = maxSum(arr, i + 1, 0);
}
return Math.max(p1, p2);
}
// 暴力方法
// 为了验证
public static int bestMedian1(int[] arr) {
int[] path = new int[arr.length];
return process(arr, 0, true, path, 0);
}
public static int process(int[] arr, int i, boolean pre, int[] path, int size) {
if (i == arr.length) {
if (size == 0) {
return 0;
}
int[] sort = new int[size];
for (int j = 0; j < size; j++) {
sort[j] = path[j];
}
Arrays.sort(sort);
return sort[(sort.length - 1) / 2];
} else {
path[size] = arr[i];
int ans = process(arr, i + 1, true, path, size + 1);
if (pre) {
ans = Math.max(ans, process(arr, i + 1, false, path, size));
}
return ans;
}
}
// 正式方法
// 时间复杂度O(N*logN)
public static int bestMedian2(int[] arr) {
int n = arr.length;
int[] sort = new int[n];
for (int i = 0; i < n; i++) {
sort[i] = arr[i];
}
Arrays.sort(sort);
// int[] arr = { 5, 3, 6, 2, 9, 7 };
// int[] sort = { 2, 3, 5, 6, 7, 9 };
// 0 1 2 3 4 5
// l r
int l = 0;
int r = n - 1;
int m = 0;
int ans = -1;
int[] help = new int[n];
int[][] dp = new int[n + 1][2];
while (l <= r) {
m = (l + r) / 2;
if (maxSum(arr, help, dp, sort[m], n) > 0) {
ans = sort[m];
l = m + 1;
} else {
r = m - 1;
}
}
return ans;
}
// 如果中位数定成median
// 如果任意相邻的两数,至少选一个,来生成序列
// 所有这样的序列中,
// 到底有没有一个序列,其中>= median的数字能达到一半以上
public static int maxSum(int[] arr, int[] help, int[][] dp, int median, int n) {
for (int i = 0; i < n; i++) {
help[i] = arr[i] >= median ? 1 : -1;
}
for (int i = n - 1; i >= 0; i--) {
dp[i][0] = help[i] + dp[i + 1][1];
dp[i][1] = Math.max(help[i] + dp[i + 1][1], dp[i + 1][0]);
}
return dp[0][1];
}
// 为了测试
public static int[] randomArray(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * v);
}
return ans;
}
// 为了测试
public static void main(String[] args) {
// 2标杆
// test = 1, 1, 1, 1, 1, 1 -> 6
// 3标杆
// test = 1, 1, 1,-1, 1, 1 -> 5
// 5标杆
// test = 1,-1, 1,-1, 1, 1 -> 4
// 6标杆
// test = -1,-1, 1,-1, 1, 1 -> 2
// 7标杆
// test = -1,-1,-1,-1, 1, 1 -> 0
// // 5 6 9 -> 6
// // 5 3 6 2 9 7 -> 2 3 5 6 7 9 -> 5
// // 3 2 7 -> 2 3 7 -> 3
// int[] test = { 5, 3, 6, 2, 9, 7 };
// int[] sort = { 2, 3, 5, 6, 7, 9 };
// int len = test.length;
// int[] help = new int[len];
// int[][] dp = new int[len + 1][2];
// System.out.println(maxSum(test, help, dp, 5, len));
// System.out.println(maxSum(test, help, dp, 7, len));
// System.out.println(maxSum(test, help, dp, 6, len));
int N = 20;
int V = 1000;
int testTimes = 5000;
System.out.println("功能测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int[] arr = randomArray(n, V);
int ans1 = bestMedian1(arr);
int ans2 = bestMedian2(arr);
if (ans1 != ans2) {
System.out.println("出错了!");
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("功能测试结束");
System.out.println("性能测试开始");
int n = 100000;
int v = 50000000;
System.out.println("数组长度 : " + n);
System.out.println("数值范围 : " + v);
int[] arr = randomArray(n, v);
long start = System.currentTimeMillis();
bestMedian2(arr);
long end = System.currentTimeMillis();
System.out.println("运行时间 : " + (end - start) + "毫秒");
System.out.println("性能测试结束");
}
}

@ -0,0 +1,128 @@
package class_2022_10_2_week;
// 定义一个二维数组N*M比如5*5数组下所示
// 0, 1, 0, 0, 0,
// 0, 1, 1, 1, 0,
// 0, 0, 0, 0, 0,
// 0, 1, 1, 1, 0,
// 0, 0, 0, 1, 0,
// 它表示一个迷宫其中的1表示墙壁0表示可以走的路
// 只能横着走或竖着走,不能斜着走
// 要求编程序找出从左上角到右下角距离最短的路线
// 测试链接 : https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下的code提交时请把主类名改成"Main"
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.PriorityQueue;
public class Code03_FindMazeMinPath {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StreamTokenizer in = new StreamTokenizer(br);
PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
while (in.nextToken() != StreamTokenizer.TT_EOF) {
int n = (int) in.nval;
in.nextToken();
int m = (int) in.nval;
int[][] map = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
in.nextToken();
map[i][j] = (int) in.nval;
}
}
ArrayList<int[]> ans = dijkstra(n, m, map);
for (int i = ans.size() - 1; i >= 0; i--) {
out.println("(" + ans.get(i)[0] + "," + ans.get(i)[1] + ")");
}
out.flush();
}
}
// n : n行
// m : m列
// map :
// 0 1 1 1
// 0 0 0 1
// 1 1 0 1
// 0 0 0 0
// list = [0,0] , [1,0], [1,1]...[3,3]
// [3,3] -> [0,0]
public static ArrayList<int[]> dijkstra(int n, int m, int[][] map) {
// (a,b) -> (c,d)
// last[c][d][0] = a
// last[c][d][1] = b
// 从哪到的当前(c,d)
int[][][] last = new int[n][m][2];
// int[] arr = {c,d,w}
// 0 1 距离
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[2] - b[2]);
boolean[][] visited = new boolean[n][m];
heap.add(new int[] { 0, 0, 0 });
ArrayList<int[]> ans = new ArrayList<>();
while (!heap.isEmpty()) {
int[] cur = heap.poll();
int x = cur[0];
int y = cur[1];
int w = cur[2];
if (x == n - 1 && y == m - 1) {
break;
}
if (visited[x][y]) {
continue;
}
// (x,y)这个点
visited[x][y] = true;
add(x, y, x - 1, y, w, n, m, map, visited, heap, last);
add(x, y, x + 1, y, w, n, m, map, visited, heap, last);
add(x, y, x, y - 1, w, n, m, map, visited, heap, last);
add(x, y, x, y + 1, w, n, m, map, visited, heap, last);
}
int x = n - 1;
int y = m - 1;
while (x != 0 || y != 0) {
ans.add(new int[] { x, y });
int lastX = last[x][y][0];
int lastY = last[x][y][1];
x = lastX;
y = lastY;
}
ans.add(new int[] { 0, 0 });
return ans;
}
// 当前是从(x,y) -> (i,j)
// 左上角 -> (x,y) , 距离是w
// 左上角 -> (x,y) -> (i,j) w+1
// 行一共有n行0~n-1有效
// 列一共有m行0~m-1有效
// map[i][j] == 1不能走是障碍
// map[i][j] == 0能走是路
// 把记录加入到堆里所以得有heap
// last[i][j][0] = x
// last[i][j][1] = y
public static void add(int x, int y,
int i, int j, int w,
int n, int m,
int[][] map,
boolean[][] visited,
PriorityQueue<int[]> heap,
int[][][] last) {
if (i >= 0 && i < n
&& j >= 0 && j < m
&& map[i][j] == 0
&& !visited[i][j]) {
heap.add(new int[] { i, j, w + 1 });
last[i][j][0] = x;
last[i][j][1] = y;
}
}
}

@ -0,0 +1,131 @@
package class_2022_10_2_week;
import java.util.PriorityQueue;
// 来自Airbnb、Uber
// 给定一个二维网格 grid 其中
// '.' 代表一个空房间
// '#' 代表一堵
// '@' 是起点
// 小写字母代表钥匙
// 大写字母代表锁
// 我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间
// 我们不能在网格外面行走,也无法穿过一堵墙
// 如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。
// 假设 k 为 钥匙/锁 的个数且满足 1 <= k <= 6
// 字母表中的前 k 个字母在网格中都有自己对应的一个小写和一个大写字母
// 换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁
// 另外,代表钥匙和锁的字母互为大小写并按字母顺序排列
// 返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 
// 测试链接https://leetcode.cn/problems/shortest-path-to-get-all-keys
public class Code04_ShortestPathToGetAllKeys {
// "@....#"
// "..b..B"
//
// @ . . . . #
// . . B . . B
public int shortestPathAllKeys(String[] grid) {
int n = grid.length;
char[][] map = new char[n][];
for (int i = 0; i < grid.length; i++) {
map[i] = grid[i].toCharArray();
}
int m = map[0].length;
return dijkstra(map, n, m);
}
public static int dijkstra(char[][] map, int n, int m) {
int startX = 0;
int startY = 0;
int keys = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map[i][j] == '@') {
startX = i;
startY = j;
}
if (map[i][j] >= 'a' && map[i][j] <= 'z') {
keys++;
}
}
}
// 如果有4把钥匙
// limit = 0000..00001111
// 如果有5把钥匙
// limit = 0000..00011111
// 也就是说所有钥匙都凑齐的状态就是limit
int limit = (1 << keys) - 1;
// 用堆来维持走过的点(dijkstra标准操作)
// 维持的信息是一个个小的4维数组arr
// arr[0] : 当前来到的x坐标
// arr[1] : 当前来到的y坐标
// arr[2] : 当前收集到的钥匙状态
// arr[3] : 从出发点到当前的距离
// 堆根据距离的从小到大组织,距离小根堆
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[3] - b[3]);
boolean[][][] visited = new boolean[n][m][1 << keys];
// startX, startY, 000000
heap.add(new int[] { startX, startY, 0, 0 });
while (!heap.isEmpty()) {
int[] cur = heap.poll();
int x = cur[0];
int y = cur[1];
int s = cur[2];
int w = cur[3];
if (s == limit) {
return w;
}
if (visited[x][y][s]) {
continue;
}
visited[x][y][s] = true;
add(x - 1, y, s, w, n, m, map, visited, heap);
add(x + 1, y, s, w, n, m, map, visited, heap);
add(x, y - 1, s, w, n, m, map, visited, heap);
add(x, y + 1, s, w, n, m, map, visited, heap);
}
return -1;
}
// 当前是由(a,b,s) -> (x,y,状态?)
// w ,从最开始到达(a,b,s)这个点的距离 -> w+1
// n,m 固定参数,防止越界
// map 地图
// visited 访问过的点,不要再加入到堆里去!
// heap, 堆!
public static void add(
int x, int y, int s,
int w, int n, int m,
char[][] map, boolean[][][] visited,
PriorityQueue<int[]> heap) {
if (x < 0 || x == n || y < 0 || y == m || map[x][y] == '#') {
return;
}
if (map[x][y] >= 'A' && map[x][y] <= 'Z') { // 锁!
// B -> 00000010
// dcba
// x,y,状 = x,y,s
// s == 00001000
// dcba
// A s & (1 << 0) != 0
// B s & (1 << 1) != 0
// D s & (1 << 3) != 0
//
if (!visited[x][y][s] && (s & (1 << (map[x][y] - 'A'))) != 0) {
heap.add(new int[] { x, y, s, w + 1 });
}
} else { // 不是锁!
// 要么是钥匙 a b c
// 要么是空房间 .
// 要么是初始位置 @
if (map[x][y] >= 'a' && map[x][y] <= 'z') {
s |= 1 << (map[x][y] - 'a');
}
if (!visited[x][y][s]) {
heap.add(new int[] { x, y, s, w + 1 });
}
}
}
}

@ -0,0 +1,202 @@
package class_2022_10_2_week;
import java.util.PriorityQueue;
// 来自华为
// 给定一个N*M的二维矩阵只由字符'O'、'X'、'S'、'E'组成
// 'O'表示这个地方是可通行的平地
// 'X'表示这个地方是不可通行的障碍
// 'S'表示这个地方有一个士兵,全图保证只有一个士兵
// 'E'表示这个地方有一个敌人,全图保证只有一个敌人
// 士兵可以在上、下、左、右四个方向上移动
// 走到相邻的可通行的平地上走一步耗费a个时间单位
// 士兵从初始地点行动时,不管去哪个方向,都不用耗费转向的代价
// 但是士兵在行动途中如果需要转向需要额外再付出b个时间单位
// 返回士兵找到敌人的最少时间
// 如果因为障碍怎么都找不到敌人,返回-1
// 1 <= N,M <= 1000
// 1 <= a,b <= 100000
// 只会有一个士兵、一个敌人
public class Code05_SoldierFindEnemy {
// 暴力dfs
// 为了验证
public static int minCost1(char[][] map, int a, int b) {
int n = map.length;
int m = map[0].length;
int startX = 0;
int startY = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map[i][j] == 'S') {
startX = i;
startY = j;
}
}
}
boolean[][][] visited = new boolean[n][m][4];
int p1 = f(map, startX, startY, 0, a, b, visited);
int p2 = f(map, startX, startY, 1, a, b, visited);
int p3 = f(map, startX, startY, 2, a, b, visited);
int p4 = f(map, startX, startY, 3, a, b, visited);
int ans = Math.min(Math.min(p1, p2), Math.min(p3, p4));
return ans == Integer.MAX_VALUE ? -1 : (ans - a);
}
public static int f(char[][] map, int si, int sj, int d, int a, int b, boolean[][][] visited) {
if (si < 0 || si == map.length || sj < 0 || sj == map[0].length || map[si][sj] == 'X' || visited[si][sj][d]) {
return Integer.MAX_VALUE;
}
if (map[si][sj] == 'E') {
return a;
}
visited[si][sj][d] = true;
int p0 = f(map, si - 1, sj, 0, a, b, visited);
int p1 = f(map, si + 1, sj, 1, a, b, visited);
int p2 = f(map, si, sj - 1, 2, a, b, visited);
int p3 = f(map, si, sj + 1, 3, a, b, visited);
if (d != 0 && p0 != Integer.MAX_VALUE) {
p0 += b;
}
if (d != 1 && p1 != Integer.MAX_VALUE) {
p1 += b;
}
if (d != 2 && p2 != Integer.MAX_VALUE) {
p2 += b;
}
if (d != 3 && p3 != Integer.MAX_VALUE) {
p3 += b;
}
int ans = Math.min(Math.min(p0, p1), Math.min(p2, p3));
ans = ans == Integer.MAX_VALUE ? ans : (ans + a);
visited[si][sj][d] = false;
return ans;
}
// 正式方法
// Dijkstra算法
public static int minCost2(char[][] map, int a, int b) {
int n = map.length;
int m = map[0].length;
int startX = 0;
int startY = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (map[i][j] == 'S') {
startX = i;
startY = j;
}
}
}
PriorityQueue<int[]> heap = new PriorityQueue<>((x, y) -> x[3] - y[3]);
// (startX, startY)
heap.add(new int[] { startX, startY, 0, 0 });
heap.add(new int[] { startX, startY, 1, 0 });
heap.add(new int[] { startX, startY, 2, 0 });
heap.add(new int[] { startX, startY, 3, 0 });
// (i,j,朝向)
boolean[][][] visited = new boolean[n][m][4];
int ans = -1;
while (!heap.isEmpty()) {
int[] cur = heap.poll();
// int x = cur[0];
// int y = cur[1];
// int 朝向 = cur[2];
// int 代价 = cur[3];
if (visited[cur[0]][cur[1]][cur[2]]) {
continue;
}
if (map[cur[0]][cur[1]] == 'E') {
ans = cur[3];
break;
}
visited[cur[0]][cur[1]][cur[2]] = true;
add(cur[0] - 1, cur[1], 0, cur[2], cur[3], a, b, map, visited, heap);
add(cur[0] + 1, cur[1], 1, cur[2], cur[3], a, b, map, visited, heap);
add(cur[0], cur[1] - 1, 2, cur[2], cur[3], a, b, map, visited, heap);
add(cur[0], cur[1] + 1, 3, cur[2], cur[3], a, b, map, visited, heap);
}
return ans;
}
// 从(x,y, preD) -> (i,j,d)
// 走格子的代价a
// 转向的代价是b
// preC + a
public static void add(
int i, int j, int d,
int preD, int preC,
int a, int b,
char[][] map, boolean[][][] visited,
PriorityQueue<int[]> heap) {
if (i < 0 || i == map.length
|| j < 0 || j == map[0].length
|| map[i][j] == 'X'
|| visited[i][j][d]) {
return;
}
int cost = preC + a;
if (d != preD) {
cost += b;
}
heap.add(new int[] { i, j, d, cost });
}
// 为了测试
public static char[][] randomMap(int n, int m) {
char[][] map = new char[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
map[i][j] = Math.random() < 0.5 ? 'O' : 'X';
}
}
int si = (int) (Math.random() * n);
int sj = (int) (Math.random() * m);
map[si][sj] = 'S';
int ei, ej;
do {
ei = (int) (Math.random() * n);
ej = (int) (Math.random() * m);
} while (ei == si && ej == sj);
map[ei][ej] = 'E';
return map;
}
public static void main(String[] args) {
int n = 3;
int m = 4;
int v = 10;
System.out.println("功能测试开始");
for (int i = 0; i < 2000; i++) {
char[][] map = randomMap(n, m);
int a = (int) (Math.random() * v) + 1;
int b = (int) (Math.random() * v) + 1;
int ans1 = minCost1(map, a, b);
int ans2 = minCost2(map, a, b);
if (ans1 != ans2) {
System.out.println("出错了");
System.out.println(ans1);
System.out.println(ans2);
}
}
System.out.println("功能测试结束");
System.out.println("性能测试开始");
n = 1000;
m = 1000;
v = 100000;
int a = (int) (Math.random() * v) + 1;
int b = (int) (Math.random() * v) + 1;
char[][] map = randomMap(n, m);
System.out.println("数据规模 : " + n + " * " + m);
System.out.println("通行代价 : " + a);
System.out.println("转向代价 : " + b);
long start = System.currentTimeMillis();
minCost2(map, a, b);
long end = System.currentTimeMillis();
System.out.println("运行时间 : " + (end - start) + "毫秒");
System.out.println("功能测试结束");
}
}

@ -2114,4 +2114,81 @@ n <= 1000
第044节 2022年10月第2周流行算法题目解析
来自小红书
小A认为如果在数组中有一个数出现了至少k次
且这个数是该数组的众数,即出现次数最多的数之一
那么这个数组被该数所支配
显然当k比较大的时候有些数组不被任何数所支配
现在小A拥有一个长度为n的数组她想知道内部有多少个区间是被某个数支配的
2 <= k <= n <= 100000
1 <= 数组的值 <= n
来自京东
实习岗位笔试题
给定一个数组arr长度为n
任意相邻的两个数里面至少要有一个被选出来,组成子序列,才是合法的!
求所有可能的合法子序列中,最大中位数是多少
中位数的定义为上中位数
[1, 2, 3, 4]的上中位数是2
[1, 2, 3, 4, 5]的上中位数是3
2 <= n <= 10^5
1 <= arr[i] <= 10^9
我写的帖子解答 : https://www.mashibing.com/question/detail/34771
定义一个二维数组N*M比如5*5数组下所示
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
它表示一个迷宫其中的1表示墙壁0表示可以走的路
只能横着走或竖着走,不能斜着走
要求编程序找出从左上角到右下角距离最短的路线
测试链接 : https://www.nowcoder.com/practice/cf24906056f4488c9ddb132f317e03bc
来自Airbnb、Uber
给定一个二维网格 grid 其中
'.' 代表一个空房间
'#' 代表一堵
'@' 是起点
小写字母代表钥匙
大写字母代表锁
我们从起点开始出发,一次移动是指向四个基本方向之一行走一个单位空间
我们不能在网格外面行走,也无法穿过一堵墙
如果途经一个钥匙,我们就把它捡起来。除非我们手里有对应的钥匙,否则无法通过锁。
假设 k 为 钥匙/锁 的个数且满足 1 <= k <= 6
字母表中的前 k 个字母在网格中都有自己对应的一个小写和一个大写字母
换言之,每个锁有唯一对应的钥匙,每个钥匙也有唯一对应的锁
另外,代表钥匙和锁的字母互为大小写并按字母顺序排列
返回获取所有钥匙所需要的移动的最少次数。如果无法获取所有钥匙,返回 -1 
测试链接https://leetcode.cn/problems/shortest-path-to-get-all-keys
来自华为
给定一个N*M的二维矩阵只由字符'O'、'X'、'S'、'E'组成
'O'表示这个地方是可通行的平地
'X'表示这个地方是不可通行的障碍
'S'表示这个地方有一个士兵,全图保证只有一个士兵
'E'表示这个地方有一个敌人,全图保证只有一个敌人
士兵可以在上、下、左、右四个方向上移动
走到相邻的可通行的平地上走一步耗费a个时间单位
士兵从初始地点行动时,不管去哪个方向,都不用耗费转向的代价
但是士兵在行动途中如果需要转向需要额外再付出b个时间单位
返回士兵找到敌人的最少时间
如果因为障碍怎么都找不到敌人,返回-1
1 <= N,M <= 1000
1 <= a,b <= 100000
只会有一个士兵、一个敌人

Loading…
Cancel
Save