小M的星球时代冒险 - MarsCode
一.bfs
字节的简单题对我来说一如既往的难啊......
最开始想的是回溯,但貌似不需要有用回溯节省新开辟空间的地方。
从做题角度,一般m*n矩阵不是bfs就是dfs或者二维动态规划。难点在于它不是简单的岛屿问题,或者最短路径什么的。难点在于每次向四个方向移动时,以前遍历过的位置还要遍历吗,应该要才行,因为不确定这个路径到遍历过的位置会不会跨越次数更少,但这样不会导致死循环吗,比如绕着个正方形一直死循环遍历。所以要很灵活的定义为,未遍历过或者跨越次数更少才允许往这个方向移动。
ERROR: 坑还多,传递的array的索引是从1开始的,还要减1处理。
import java.util.ArrayDeque;
import java.util.Queue;
public class Main {
// 上下左右
public static final int[] dx = new int[] { -1, 1, 0, 0 };
public static final int[] dy = new int[] { 0, 0, -1, 1 };
public static int[] solution(int n, int m, int[] a, int[] b, int q, int[][] array) {
// Edit your code here
int[] ans = new int[q];
for (int i = 0; i < q; i++) {
ans[i] = bfs(n, m, a, b, array[i]);
}
return ans;
}
public static int bfs(int n, int m, int[] a, int[] b, int[] arr) {
int[][] visited = new int[n][m];
// 初始化
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
visited[i][j] = -1;
}
}
int x1 = arr[0]-1, y1 = arr[1] - 1;
visited[x1][y1] = 0;
int[] point1 = new int[]{x1, y1};
int x2, y2;
//队列
Queue<int[]> queue = new ArrayDeque<>();
queue.add(point1);
while(!queue.isEmpty()) {
point1 = queue.poll();
// 判断地形
boolean p1 = (a[point1[0]] == b[point1[1]]?true:false);
for(int i = 0; i < 4; i++) {
x2 = (point1[0] + dx[i] + n)%n;
y2 = (point1[1] + dy[i] + m)%m;
// 判断地形
boolean p2 = (a[x2] == b[y2]?true:false);
//是否跨越地形
int cnt = (p1 == p2 ? 0 : 1);
// 未访问过,或者是跨越次数更少的路径
if(visited[x2][y2] == -1 || visited[point1[0]][point1[1]] + cnt < visited[x2][y2]) {
visited[x2][y2] = visited[point1[0]][point1[1]] + cnt;
queue.add(new int[]{x2, y2});
}
}
}
return visited[arr[2]-1][arr[3]-1];
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(java.util.Arrays.equals(solution(3, 4, new int[] { 0, 1, 1 }, new int[] { 0, 1, 1, 0 }, 2,
new int[][] { { 2, 1, 3, 3 }, { 2, 4, 2, 1 } }), new int[] { 1, 0 }));
System.out.println(java.util.Arrays.equals(solution(3, 4, new int[] { 0, 1, 1 }, new int[] { 0, 0, 1, 1 }, 2,
new int[][] { { 1, 2, 2, 2 }, { 2, 1, 2, 3 } }), new int[] { 1, 1 }));
}
}
当然也可以用手动栈或者递归dfs实现。
二.dfs手动栈实现
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
// 上下左右
public static final int[] dx = new int[] { -1, 1, 0, 0 };
public static final int[] dy = new int[] { 0, 0, -1, 1 };
public static int[] solution(int n, int m, int[] a, int[] b, int q, int[][] array) {
// Edit your code here
int[] ans = new int[q];
for (int i = 0; i < q; i++) {
ans[i] = dfs(n, m, a, b, array[i]);
}
return ans;
}
public static int dfs(int n, int m, int[] a, int[] b, int[] arr) {
int[][] visited = new int[n][m];
// 初始化
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
visited[i][j] = -1;
}
}
int x1 = arr[0]-1, y1 = arr[1] - 1;
visited[x1][y1] = 0;
int[] point1 = new int[]{x1, y1};
int x2, y2;
int px2 = arr[2]-1,py2 = arr[3] - 1;
//栈
Deque<int[]> stack = new ArrayDeque<>();
stack.add(point1);
while(!stack.isEmpty()) {
point1 = stack.pop();
// 判断地形
boolean p1 = (a[point1[0]] == b[point1[1]]?true:false);
if(point1[0] == px2 && point1[1] == py2)
continue;
for(int i = 0; i < 4; i++) {
x2 = (point1[0] + dx[i] + n)%n;
y2 = (point1[1] + dy[i] + m)%m;
// 判断地形
boolean p2 = (a[x2] == b[y2]?true:false);
//是否跨越地形
int cnt = (p1 == p2 ? 0 : 1);
// 未访问过,或者是跨越次数更少的路径
if(visited[x2][y2] == -1 || visited[point1[0]][point1[1]] + cnt < visited[x2][y2]) {
visited[x2][y2] = visited[point1[0]][point1[1]] + cnt;
stack.push(new int[]{x2, y2});
}
}
}
return visited[arr[2]-1][arr[3]-1];
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(java.util.Arrays.equals(solution(3, 4, new int[] { 0, 1, 1 }, new int[] { 0, 1, 1, 0 }, 2,
new int[][] { { 2, 1, 3, 3 }, { 2, 4, 2, 1 } }), new int[] { 1, 0 }));
System.out.println(java.util.Arrays.equals(solution(3, 4, new int[] { 0, 1, 1 }, new int[] { 0, 0, 1, 1 }, 2,
new int[][] { { 1, 2, 2, 2 }, { 2, 1, 2, 3 } }), new int[] { 1, 1 }));
}
}
三,递归版dfs
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
// 上下左右
public static final int[] dx = new int[] { -1, 1, 0, 0 };
public static final int[] dy = new int[] { 0, 0, -1, 1 };
public static int[] solution(int n, int m, int[] a, int[] b, int q, int[][] array) {
// Edit your code here
int[] ans = new int[q];
for (int i = 0; i < q; i++) {
int[][] visited = new int[n][m];
// 初始化
for (int j = 0; j < n; j++) {
for (int k = 0; k < m; k++) {
visited[j][k] = -1;
}
}
visited[array[i][0]-1][array[i][1]-1]= 0;
dfs(a, b, visited, new int[]{array[i][0]-1, array[i][1]-1},new int[]{array[i][2]-1, array[i][3]-1});
ans[i] = visited[array[i][2]-1][array[i][3]-1];
}
return ans;
}
public static void dfs(int[] a, int[] b, int[][] visited, int[] cur,
int[] dst) {
if(cur[0] == dst[0] && cur[1] == dst[1])
return;
// 判断地形
boolean p1 = (a[cur[0]] == b[cur[1]]?true:false);
int n = a.length, m = b.length;
for(int i = 0; i < 4; i++) {
int x2 = (cur[0] + dx[i] + n)%n;
int y2 = (cur[1] + dy[i] + m)%m;
// 判断地形
boolean p2 = (a[x2] == b[y2]?true:false);
//是否跨越地形
int cnt = (p1 == p2 ? 0 : 1);
// 未访问过,或者是跨越次数更少的路径
if(visited[x2][y2] == -1 || visited[cur[0]][cur[1]] + cnt < visited[x2][y2]) {
visited[x2][y2] = visited[cur[0]][cur[1]] + cnt;
dfs(a, b, visited, new int[]{x2, y2}, dst);
}
}
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(java.util.Arrays.equals(solution(3, 4, new int[] { 0, 1, 1 }, new int[] { 0, 1, 1, 0 }, 2,
new int[][] { { 2, 1, 3, 3 }, { 2, 4, 2, 1 } }), new int[] { 1, 0 }));
System.out.println(java.util.Arrays.equals(solution(3, 4, new int[] { 0, 1, 1 }, new int[] { 0, 0, 1, 1 }, 2,
new int[][] { { 1, 2, 2, 2 }, { 2, 1, 2, 3 } }), new int[] { 1, 1 }));
}
}