小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 }));
    }
}

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐