矩阵的leetcode

62 不同路径,用动态规划做很简单

class Solution {
    int res = 0;
    public int uniquePaths(int m, int n) {        
        int[][] matrix = new int[m][n];
        //matrix是dp数组,因为从固定方向移动,所以可以这么初始化
        //如果四个方向都可以移动,这么做不可以
        for(int i = 0; i < m; i++) matrix[i][0] = 1;
        for(int i = 0; i < n; i++) matrix[0][i] = 1;
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++){
                //从0位置到i, j 位置i, j 有几条路径
                //它可以是从两个方向得到的,从上,i- 1, 从左 j - 1
                matrix[i][j] = matrix[i - 1][j] + matrix[i][j - 1];
            }
        }
       
        return matrix[m - 1][n - 1];

    }
   
}

63 不同路径

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {

        int m = obstacleGrid.length, n = obstacleGrid[0].length;
        int[][] matrix = new int[m][n];
        //在初始化第一行和第一列时也要注意如果遇到障碍物直接退出 
        for(int i = 0; i < m; i++) {
            if(obstacleGrid[i][0]==1) break;
            matrix[i][0] = 1;
        }

        for(int i = 0; i < n; i++){
            if(obstacleGrid[0][i]==1) break;
            matrix[0][i] = 1;
        } 
        for(int i = 1; i < m; i++){
            for(int j = 1; j < n; j++){
                //从0位置到i, j 位置i, j 有几条路径
                //它可以是从两个方向得到的,从上,i- 1, 从左 j - 1
                if(obstacleGrid[i][j] == 1) continue;
                else matrix[i][j] = matrix[i - 1][j] + matrix[i][j - 1];
            }
        }
       
        return matrix[m - 1][n - 1];

  
    }
}

64 最小路径和

同剑指offer 47. 礼物的最大价值(动态规划)

题目说明:从棋盘的左上角开始拿格子里的礼物,并每次 向右 或者向下 移动一格、直到到达棋盘的右下角。
根据题目说明,易得某单元格只可能从上边单元格或左边单元格到达。

设 f(i, j)f(i,j) 为从棋盘左上角走至单元格 (i ,j)(i,j) 的礼物最大累计价值,易得到以下递推关系:f(i,j)f(i,j) 等于 f(i,j-1)f(i,j−1) 和 f(i-1,j)f(i−1,j) 中的较大值加上当前单元格礼物价值 grid(i,j)grid(i,j) 。

f(i,j) = max[f(i,j-1), f(i-1,j)] + grid(i,j)

class Solution {
    public int maxValue(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        for(int j = 1; j < n; j++) // 初始化第一行
            grid[0][j] += grid[0][j - 1];
        for(int i = 1; i < m; i++) // 初始化第一列
            grid[i][0] += grid[i - 1][0];
        for(int i = 1; i < m; i++)
            for(int j = 1; j < n; j++) 
                //从上面和左面中选择最大的一个
                grid[i][j] += Math.max(grid[i][j - 1], grid[i - 1][j]);
        return grid[m - 1][n - 1];
    }
}

剑指 Offer 04. 二维数组中的查找

行从左到右递增,列从上到下递增

class Solution {
    public boolean findNumberIn2DArray(int[][] matrix, int target) {
        //根据矩阵的性质可得,左下角/右上角的元素上边和左边/下边和右边呈现出不同的元素递增关系
        //我这里边先的是从左下角
        int i = matrix.length - 1, j = 0;
        while(i >= 0 && j < matrix[0].length)
        {
            //如果它比目标元素大,向上一行
            if(matrix[i][j] > target) i--;
            //如果它比目标元素小,则向右移动一列
            else if(matrix[i][j] < target) j++;
            //如果存在直接返回真
            else return true;
        }
        return false;
    }
}

剑指offer 12. 矩阵中的路径( DFS + 剪枝 ,清晰图解)

board数组防止数据重复访问

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();
        //因为可以从矩阵中任意点开始,所以要两层for循环遍历所有节点
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                //如果有直接符合条件的,直接返回
                if(dfs(board, words, i, j, 0)) return true;
            }
        }
        return false;
    }
    boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        //超过边界4个边界,提前剪枝,当前元素和目标元素不同时也退出
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
        //如果遍历了word的长度,则说明找到了,直接返回,也属于提前剪枝
        if(k == word.length - 1) return true;
        board[i][j] = '\0';
        //寻找四个方向的,有一个为真就可以
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = word[k];
        return res;
    }
}

剑指offer13机器人的运动范围

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

class Solution {
    public int movingCount(int m, int n, int k) {
        //标记当前格子是否被访问过
        boolean[][] visited = new boolean[m][n];
        //参数:visited数组、m、n、k、当前所处格子,只往右下走
        return dfs(visited, m, n, k, 0, 0);
    }

    private int dfs(boolean[][] visited, int m, int n, int k, int i, int j){
        //递归终止条件
        if(i >= m ||  j >= n || bitSum(i) + bitSum(j) > k || visited[i][j]) return 0;


        visited[i][j] = true;

        //当前格 + 往下走 + 往右走
        return 1 + dfs(visited, m, n, k, i + 1, j) + dfs(visited, m, n, k, i, j + 1);
    }

    private int bitSum(int x){
        int sum = 0;
        while(x != 0){
            sum += x % 10;
            x /= 10;
        }
        return sum;
    }
}


剑指 Offer 29. 顺时针打印矩阵   做法:模拟 

54. 螺旋矩阵 59. 螺旋矩阵 II   类似

class Solution {
    public int[] spiralOrder(int[][] matrix) {
        if(matrix.length == 0) return new int[0];
        //设置矩阵四个边界的值
        int l = 0, r = matrix[0].length - 1, t = 0, b = matrix.length - 1, x = 0;
        int[] res = new int[(r + 1) * (b + 1)];
        while(true) {
            //第一次,从左边到右边
            for(int i = l; i <= r; i++) res[x++] = matrix[t][i]; // left to right.
            //第二次,先遍历上边界++是否大于下边界,如果是再退出 
            if(++t > b) break;
            for(int i = t; i <= b; i++) res[x++] = matrix[i][r]; // top to bottom.
            //第三次,先遍历左边界是否比右边界--要大,如果是则退出  
            if(l > --r) break;
            for(int i = r; i >= l; i--) res[x++] = matrix[b][i]; // right to left.
            //第四次,先遍历上边界是否大于下边界--,如果是则退出 
            if(t > --b) break;
            for(int i = b; i >= t; i--) res[x++] = matrix[i][l]; // bottom to top.
            //第一次没有判断条件在这里了,判断左边界++是否大于右边界,如果是则退出 
            if(++l > r) break;
        }
        return res;
    }
}

岛屿数量 

200. 岛屿数量

class Solution {
    public int numIslands(char[][] grid) {
        int count = 0;
        for(int i = 0; i < grid.length; i++) {
            for(int j = 0; j < grid[0].length; j++) {
                if(grid[i][j] == '1'){
                    dfs(grid, i, j);
                    count++;
                }
            }
        }
        return count;
    }
    private void dfs(char[][] grid, int i, int j){
        if(i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') return;
        //遍历完为1的区域让它变为0
        grid[i][j] = '0';
        dfs(grid, i + 1, j);
        dfs(grid, i, j + 1);
        dfs(grid, i - 1, j);
        dfs(grid, i, j - 1);
    }
}

695. 岛屿的最大面积

岛屿的最大面积

是200题的另一个问法,问这些岛屿中面积最大的是哪个?

class Solution {
    public int maxAreaOfIsland(int[][] grid) {
        if(grid == null || grid.length == 0) return 0;

        int m = grid.length, n = grid[0].length;
        int maxArea = 0; //记录最大岛屿面积,最终返回

        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(grid[i][j] == 1){
                    //以陆地为中心向四周找
                    int curArea = dfs(grid, i, j);

                    //更新最大岛屿面积
                    maxArea = Math.max(maxArea, curArea);
                }
            }
        }
        return maxArea;
    }

    /**dfs向四周找陆地 */
    private int dfs(int[][] grid, int i, int j){
        //递归终止:越界 或者 走到了水域
        if(i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] == 0) return 0;

        grid[i][j] = 0; //标记为0,防止重复访问

        //上下左右搜索
        int up = dfs(grid, i - 1, j);
        int down = dfs(grid, i + 1, j);
        int left = dfs(grid, i, j - 1);
        int right = dfs(grid, i, j + 1);
        
        return up + down + left + right + 1;
    }
}

矩阵中的最长递增路径

这个题,因为起点可以不是0,0 相对递归来説要简单

矩阵中的最长递增路径

class Solution {
     
    public int longestIncreasingPath(int[][] matrix) {
        if(matrix.length == 1 && matrix[0].length == 1) return matrix[0][0];
        int row = matrix.length, column = matrix[0].length;
        int res = Integer.MIN_VALUE;           
             int[][] memo = new int[n][n];
            int res = 0;
            for(int i = 0; i < n; i++) {
                for(int j = 0; j < n; j++) {
                    // 若没有搜索过才需要进行搜索
                    if(memo[i][j] == 0) {
                        res = Math.max(res, dfs(i, j,memo, matrix));
                    }
                    // 这里为什么没有比较memo[i][j]!=0的情况?
                    // 因为后面matrix[nextI][nextJ]为起点的路径总比matrix[i][j]为起点的短
                    // 满足matrix[nextI][nextJ]>matrix[i][j]才会进行dfs的
                }
            }
            return res;
        }

    }
    /*
    返回以matrix[i][j]为起点的最长递增路径
    */
    private static int dfs(int i, int j, int[][]memo,int[][] matrix) {
        // 若之前搜索过了直接返回之前存储的最大长度
        if(memo[i][j] != 0) {
            return memo[i][j];
        }
        int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, 1}, {0, -1}};
        // 以matrix[i][j]为起点的最长递增路径
        int maxLen = 1;
        int n = matrix.length;
        for(int[] dir : dirs) {
            int nextI = i + dir[0];
            int nextJ = j + dir[1];
            if(nextI >= 0 && nextI < n && nextJ >= 0 && nextJ < n
                    && matrix[nextI][nextJ] > matrix[i][j]) {
                // 选择4个方向的最大路径的最大值作为maxLen
                maxLen = Math.max(maxLen, dfs(nextI, nextJ,memo ,matrix) + 1);
            }
        }
        // 将以matrix[i][j]为起点的最长递增路径存储在memo[i][j]中
        // 注意:在递归过程中将matrix[nextI,nextJ]为起点的最长路径都存储在memo了
        memo[i][j] = maxLen;
        // 返回该最长路径长度
        return maxLen;
    }

走迷宫的最短路径

public class Main {

    private static int min=8888,total=0;
    static int Dire[][]={{0,1},{1,0},{0,-1},{-1,0}};

    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String input = "";
        while (null != (input = reader.readLine())) {
            int n = Integer.parseInt(input);

            int[][] arr = new int[n][n];

            //int res = 0;
            for (int k = 0; k < n; k++) {
                String[] tmp = reader.readLine().split(" ");
                for (int j = 0; j < n; j++) {
                    arr[k][j] = Integer.parseInt(tmp[j]);
                }
            }
            boolean[][] b = new boolean[n][n];
            b[0][0] = true;
            if (arr[0][0] == 0) {
                System.out.println(0);
                System.out.println(0);
            }
            if (n == 1 && arr[0][0] == 1) {
                System.out.println(1);
                System.out.println(1);
            }
            dfs(arr, 0, 0, 0, b);
            System.out.println(min);
            System.out.println(total);

        }}


    public static void dfs(int[][] matrix,int x,int y,int step,boolean[][] book){
        int tx,ty;

        if(x==matrix.length- 1 &&y==matrix.length - 1 ) {
            if(min>step) {
                min=step;
                total=0;
            }if(min == step) {
                total++;
            }

            return;
        }
        else {
            for(int i=0;i<4;i++){
                tx=x+Dire[i][0];        //改变坐标
                ty=y+Dire[i][1];

                if(tx<matrix.length && tx>=0 && ty>=0 && ty<matrix.length  &&matrix[tx][ty]==1&&book[tx][ty]==false){  //判断当前即将移动的坐标是否满足条件
                    book[tx][ty]=true;              //递去过程中 标记当前位置已走过
                    dfs(matrix,tx,ty,step+1, book);
                    book[tx][ty]=false;             //归来过程中 取消标记
                }

            }
            return;
        }
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值