第一部分:矩阵打印问题
1. 螺旋打印矩阵
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
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. 搜索二维矩阵
每行中的整数从左到右按升序排列。
每行的第一个整数大于前一行的最后一个整数。
//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
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
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小的数
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
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. 矩阵中的单词路径
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. 矩阵中的最长递增路径
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. 最大子数组和问题延边成最大子矩阵和问题
当之前已有的数组和大于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;
}
}
//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;
}