常见面试算法题之矩阵处理专题

164 阅读2分钟

第一部分:矩阵打印问题

1. 螺旋打印矩阵

leetcode-cn.com/problems/sp…

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> res = new ArrayList<>();
        int row = matrix.length;
        if(row == 0 ) return res;
        int col = matrix[0].length;

        int l = 0 , r = col-1; // l 和 r 分别表示 左边界和有边界
        int t = 0 , b = row-1; // t 和 b 分别表示 上边界和下边界
        while(true){
            for(int i = l ; i <= r ; i++) res.add(matrix[t][i]);
            if(++t > b) break;
            for(int i = t ; i <= b ; i++) res.add(matrix[i][r]);
            if(--r < l) break;
            for(int i = r ; i >= l ; i--) res.add(matrix[b][i]);
            if(--b < t) break;
            for(int i = b ; i >= t ; i--) res.add(matrix[i][l]);
            if(++l > r) break;
        }
        return res;
        
    }
}

2. 螺旋打印矩阵2

leetcode-cn.com/problems/sp…

class Solution {
    public int[][] generateMatrix(int n) {
        if(n == 0) return new int[0][0];
        int[][] res = new int[n][n];
        int l = 0 , r = n-1;
        int t = 0 , b = n-1;
        int index = 1;
        while(true){
            for(int i = l ; i <= r ; i++) res[t][i] = index++;
            if(++t > b) break;
            for(int i = t ; i <= b ; i++) res[i][r] = index++;
            if(--r < l) break;
            for(int i = r ; i >= l ; i--) res[b][i] = index++;
            if(--b < t) break;
            for(int i = b ; i >= t ; i--) res[i][l] = index++;
            if(++l > r) break;
        }
        return res;
    }
}

第二部分:矩阵搜索问题

1. 搜索二维矩阵

leetcode-cn.com/problems/se…

每行中的整数从左到右按升序排列。

每行的第一个整数大于前一行的最后一个整数。


//1.二分查找
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int m = matrix.length; //行数
        int n = matrix[0].length; //列数
        int l = 0 , r = m *n -1;
        while(l < r){
            int mid = l + r + 1 >> 1;
            if(matrix[mid / n][ mid % n] > target) r = mid-1;
            else l = mid;
        }

        return matrix[l/n][l%n] == target;

    }
}

//2.正常的矩阵搜索
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int row = matrix.length;
        if(row == 0) return false;
        int col = matrix[0].length;

        int l = 0 , r = col-1;
        while(l < row && r >= 0){
            if(matrix[l][r] > target) r--;
            else if(matrix[l][r] < target) l++;
            else return true;
        }
        return false;

    }
}

2. 搜索二维矩阵2

leetcode-cn.com/problems/se…

每行的元素从左到右升序排列。
每列的元素从上到下升序排列。

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int row = matrix.length;
        if(row == 0) return false;
        int col = matrix[0].length;

        int l = 0 , r = col-1;
        while(l < row && r >= 0){
            if(matrix[l][r] > target) r--;
            else if(matrix[l][r] < target) l++;
            else return true;
        }
        return false;
    }
}

3. 有序二维矩阵中第k小的数

leetcode-cn.com/problems/kt…

class Solution {
    //二分查找
    public int kthSmallest(int[][] matrix, int k) {
        int row = matrix.length;
        if(row == 0) return 0;
        int col = matrix[0].length;
        int l = matrix[0][0] , r = matrix[row-1][col-1];
        while(l < r){
            int mid = l + r >> 1;
    
            int count = 0;
            for(int i = 0 ; i < row ; i++){
                for(int j = 0 ; j < col ; j++){
                    if(matrix[i][j] <= mid) count++;
                }
            }
            
            if(count < k) l = mid+1; //说明在右边
            else r = mid;
        }
        return l; // 如何保证最后的l一定是矩阵中的值
    }
}

4. 矩阵置0

leetcode-cn.com/problems/se…

class Solution {
    public void setZeroes(int[][] matrix) {
        int row = matrix.length;
        if(row == 0) return;
        int col = matrix[0].length;
        boolean row0 = false , col0 = false;
        //1. 先判断第一行第一列是否有0
        for(int i = 0 ; i < row ;i++){
            for(int j = 0 ; j < col ;j++){
                if(matrix[i][j] == 0){
                    if(i == 0) row0 = true;
                    if(j == 0) col0 = true;
                    matrix[0][j] = matrix[i][0] = 0;
                }
            }
        }

        //2. 如果首行首列为0,则置为0
        for(int i = 1; i < row ; i++){
            for(int j = 1 ; j < col ; j++){
                if(matrix[0][j] == 0 || matrix[i][0] == 0) matrix[i][j] = 0;
            }
        }

        //3. 把第一行第一列置为0
        if(col0){
            for(int i = 0 ; i < row ; i++) matrix[i][0] = 0;
        }
        if(row0){
            for(int i = 0 ; i < col ; i++) matrix[0][i] = 0;
        }
    }
}

第三部分:矩阵路径问题

1. 矩阵中的单词路径

leetcode-cn.com/problems/ju…

class Solution {
    public boolean exist(char[][] board, String word) {
        int m = board.length;
        if(m == 0) return false;
        int n = board[0].length;

        boolean[][] isv = new boolean[m][n];
        for(int i = 0 ; i < m ; i++){
            for(int j = 0 ; j < n ; j++){
                if(board[i][j] == word.charAt(0) && dfs(i , j , 0, word ,board, isv))  return true;
            }
        }
        return false;
    }

    boolean dfs(int i , int j , int index , String word , char[][] board, boolean[][] isv){
        if (index == word.length()) return true;
        
        if(i < 0 || i >= board.length || j < 0 || j >= board[0].length) return false;
        if(board[i][j] != word.charAt(index) ||  isv[i][j]) return false;
        isv[i][j] = true;
        if(dfs(i+1,j,index+1,word,board,isv)
         ||dfs(i-1,j,index+1,word,board,isv)
         ||dfs(i,j+1,index+1,word,board,isv)
         ||dfs(i,j-1,index+1,word,board,isv)) return true;

        isv[i][j] = false;
        return false;
    }
}

2. 矩阵中的最长递增路径

leetcode-cn.com/problems/lo…

class Solution {
    public int longestIncreasingPath(int[][] matrix) {
        int row = matrix.length;
        if(row == 0) return 0;
        int col = matrix[0].length;

        int[][] dp = new int[row][col];
        int res = 0;
        for(int i = 0 ; i  < row ; i++){
            for(int j = 0 ; j < col ; j++){
                res = Math.max(res , dfs(i , j , Integer.MIN_VALUE , matrix , dp));
            }
        }
        return res;
    }

    int dfs(int i , int  j , int curNum , int[][] matrix , int[][] dp){
        if(i < 0 || i >= matrix.length || j < 0 || j >= matrix[0].length) return 0;
        if(matrix[i][j] <= curNum) return 0;
        if(dp[i][j] != 0) return dp[i][j];
        int res = 0;
        res = Math.max(res , dfs(i+1 , j , matrix[i][j] , matrix , dp));
        res = Math.max(res , dfs(i-1 , j , matrix[i][j] , matrix , dp));
        res = Math.max(res , dfs(i , j+1 , matrix[i][j] , matrix , dp));
        res = Math.max(res , dfs(i , j-1 , matrix[i][j] , matrix , dp));
        dp[i][j] = res+1;
        return res+1;
    }
}

第四部分:子矩阵问题

1. 最大子数组和问题延边成最大子矩阵和问题

leetcode-cn.com/problems/ma…

当之前已有的数组和大于0时,则它必然对于此时的和有贡献,
因此在其基础上累加(if sum > 0 : sum += nums[i]);
当之前已有的数组和小于0时,则此时应该另起炉灶(if sum < 0 : sum = nums[i])。

class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0];
        int sum = nums[0];
        for (int i = 1; i < nums.length; i++) {
            sum = nums[i] + (sum > 0 ? sum : 0);
            max = Math.max(max, sum);
        }
        return max;
    }
}

求最大子数组位置
class Solution {
    public int[] maxSubArray(int[] nums) {
        int start = 0;
        int sum = nums[0];
        int max = nums[0];
        int[] res = new int[2];
        for (int i = 1; i < nums.length; i++) {
            if (sum > 0) {
            	// 之前的数组和有"贡献",因此在其基础上累加
                sum += nums[i];
            } else {
            	// 之前的数组无"贡献",因此另起炉灶
                sum = nums[i];
                start = i;
            }
            if (sum > max) {
                max = sum;
                res[0] = start;
                res[1] = i;
            }
        }
        return res;
    }
}

leetcode-cn.com/problems/ma…

image.png


        //9,-8,1,3,-2
        //-3,7,6,-2,4
        //6,-4,-4,8,-7
       变成:
        /*
        *   [0, 0, 0, 0, 0]
            [9, -8, 1, 3, -2]
            [6, -1, 7, 1, 2]
            [12, -5, 3, 9, -5]
        * */

public int[] getMaxMatrix(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        int[] res = new int[4];
        int max = matrix[0][0];

        int[][] preSum = new int[m+1][n];
        for (int i = 1 ; i < m+1 ; i++){
            for (int j = 0 ; j < n ; j++)
                preSum[i][j] = preSum[i-1][j] + matrix[i-1][j];
        }

//        for (int i = 0; i < preSum.length; i++) {
//            System.out.println(Arrays.toString(preSum[i]));
//        }

        for (int top = 0; top < m; top++) {
            for (int bottom = top; bottom < m; bottom++) {
                int[] nums = new int[n];
                for (int i = 0; i < n; i++) {
                    nums[i] = preSum[bottom+1][i] - preSum[top][i];
                }

                int start = 0 , sum = nums[0];
                for (int i = 1; i < n; i++) {
                    if (sum > 0) sum+=nums[i];
                    else{
                        sum = nums[i];
                        start = i;
                    }
                    if (sum > max){
                        max = sum;
                        res[0] = top;
                        res[1] = start;
                        res[2] = bottom;
                        res[3] = i;
                    }
                }
            }
        }
        return  res;
    }