目录
[1. 图像渲染](#1. 图像渲染)
[1.1 解题思路](#1.1 解题思路)
[1.2 代码实现](#1.2 代码实现)
[2. 岛屿数量](#2. 岛屿数量)
[2.1 解题思路](#2.1 解题思路)
[2.2 代码实现](#2.2 代码实现)
[3. 岛屿的最大面积](#3. 岛屿的最大面积)
[3.1 解题思路](#3.1 解题思路)
[3.2 代码实现](#3.2 代码实现)
[4. 被围绕的区域](#4. 被围绕的区域)
[4.1 解题思路](#4.1 解题思路)
[4.2 代码实现](#4.2 代码实现)
[5. 太平洋大西洋水流问题](#5. 太平洋大西洋水流问题)
[5.1 解题思路](#5.1 解题思路)
[5.2 代码实现](#5.2 代码实现)
[6. 扫雷游戏](#6. 扫雷游戏)
[6.1 解题思路](#6.1 解题思路)
[6.2 代码实现](#6.2 代码实现)
[7. 衣橱整理](#7. 衣橱整理)
[7.1 解题思路](#7.1 解题思路)
[7.2 代码实现](#7.2 代码实现)
[8. 记忆化搜索--斐波那契数列](#8. 记忆化搜索--斐波那契数列)
[8.1 解题思路](#8.1 解题思路)
[8.2 代码实现](#8.2 代码实现)
[9. 不同路径](#9. 不同路径)
[9.1 解题思路](#9.1 解题思路)
[9.2 代码实现](#9.2 代码实现)
[10. 最长递增子序列](#10. 最长递增子序列)
[10.1 解题思路](#10.1 解题思路)
[10.2 代码实现](#10.2 代码实现)
[11. 猜数字大小2](#11. 猜数字大小2)
[11.1 解题思路](#11.1 解题思路)
[11.2 代码实现](#11.2 代码实现)
[12. 矩阵中的最长递增路径](#12. 矩阵中的最长递增路径)
[12.1 解题思路](#12.1 解题思路)
[12.2 代码实现](#12.2 代码实现)
1. 图像渲染
1.1 解题思路

1.2 代码实现
java
class Solution {
int m = 0;
int n = 0;
int[] dx = { 0, 0, -1, 1 };
int[] dy = { -1, 1, 0, 0 };
//记录sr,sc位置的原来数据
int tmp;
public int[][] floodFill(int[][] image, int sr, int sc, int color) {
if (image[sr][sc] == color) {
return image;
}
m = image.length;
n = image[0].length;
tmp = image[sr][sc];
image[sr][sc] = color;
dfs(image, sr, sc, color);
return image;
}
public void dfs(int[][] image, int sr, int sc, int color) {
for (int i = 0; i < 4; i++) {
int x = sr + dx[i];
int y = sc + dy[i];
if (x >= 0 && x < m && y >= 0 && y < n && image[x][y] == tmp) {
image[x][y] = color;
dfs(image, x, y, color);
}
}
}
}
2. 岛屿数量
2.1 解题思路
这道题跟上面一道题类似。
2.2 代码实现
java
class Solution {
boolean[][] check;
int m;
int n;
int sum;
int[] dx = {0,0,-1,1};
int[] dy = {-1,1,0,0};
public int numIslands(char[][] grid) {
m = grid.length;
n = grid[0].length;
check = new boolean[m][n];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(check[i][j] == false && grid[i][j] == '1') {
dfs(grid,i,j);
sum++;
}
}
}
return sum;
}
public void dfs(char[][] grid, int i, int j) {
check[i][j] = true;
for(int k = 0; k < 4; k++) {
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n &&
check[x][y] == false && grid[x][y] == '1') {
dfs(grid,x,y);
}
}
}
}
3. 岛屿的最大面积
3.1 解题思路
与上面两道题类似,只需要设置一个变量来记录岛屿的面积。
3.2 代码实现
java
class Solution {
boolean[][] check;
int m,n;
int[] dx = {0,0,-1,1};
int[] dy = {-1,1,0,0};
int tmp = 0;
public int maxAreaOfIsland(int[][] grid) {
m = grid.length;
n = grid[0].length;
check = new boolean[m][n];
int max = 0;
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(check[i][j] == false && grid[i][j] == 1) {
dfs(grid,i,j);
max = Math.max(tmp,max);
tmp = 0;
}
}
}
return max;
}
public void dfs(int[][] grid, int i, int j) {
check[i][j] = true;
tmp++;
for(int k = 0; k < 4; k++) {
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n &&
check[x][y] == false && grid[x][y] == 1) {
dfs(grid,x,y);
}
}
}
}
4. 被围绕的区域
4.1 解题思路

4.2 代码实现
java
class Solution {
int m, n;
int[] dx = { 0, 0, -1, 1 };
int[] dy = { -1, 1, 0, 0 };
public void solve(char[][] board) {
m = board.length;
n = board[0].length;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if ((i == 0 || i == m - 1 || j == 0 || j == n - 1) &&
board[i][j] == 'O') {
dfs(board, i, j);
}
}
}
//将里面的字母复原
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if(board[i][j] == '.') {
board[i][j] = 'O';
}else if(board[i][j] == 'O') {
board[i][j] = 'X';
}
}
}
}
public void dfs(char[][] board, int i, int j) {
board[i][j] = '.';
for (int k = 0; k < 4; k++) {
int x = i + dx[k];
int y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'O') {
dfs(board, x, y);
}
}
}
}
5. 太平洋大西洋水流问题
5.1 解题思路

5.2 代码实现
java
class Solution {
int m,n;
int[] dx = {0,0,-1,1};
int[] dy = {-1,1,0,0};
public List<List<Integer>> pacificAtlantic(int[][] heights) {
m = heights.length;
n = heights[0].length;
boolean[][] pac = new boolean[m][n];
boolean[][] atl = new boolean[m][n];
//太平洋第一行
for(int j = 0; j < n; j++) {
dfs(heights,0,j,pac);
}
//太平洋第一列
for(int i = 0; i < m; i++) {
dfs(heights,i,0,pac);
}
//大西洋最后一行
for(int j = 0; j < n; j++) {
dfs(heights,m-1,j,atl);
}
//大西洋最后一列
for(int i = 0; i < m; i++) {
dfs(heights,i,n-1,atl);
}
//得到最后结果
List<List<Integer>> ret = new ArrayList<>();
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
if(pac[i][j] && atl[i][j]) {
List<Integer> tmp = new ArrayList<>();
tmp.add(i);
tmp.add(j);
ret.add(tmp);
}
}
}
return ret;
}
public void dfs(int[][] heights, int i, int j, boolean[][] check) {
check[i][j] = true;
for(int k = 0; k < 4; k++) {
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n &&
heights[x][y] >= heights[i][j] && check[x][y] == false) {
dfs(heights,x,y,check);
}
}
}
}
6. 扫雷游戏
6.1 解题思路
这道题按照题意,一步一步来编写代码,一定要先读懂题目后才编写代码。
6.2 代码实现
java
class Solution {
int m, n;
int[] dx = {0, 0, -1, 1, -1, 1, -1, 1 };
int[] dy = {-1, 1, 0, 0, -1, -1, 1, 1 };
public char[][] updateBoard(char[][] board, int[] click) {
m = board.length;
n = board[0].length;
int x = click[0];
int y = click[1];
//直接点到地雷
if(board[x][y] == 'M') {
board[x][y] = 'X';
return board;
}
//未点到地雷
dfs(board,x,y);
return board;
}
public void dfs(char[][] board, int i, int j) {
//统计当前周围地雷数量
int count = 0;
for (int k = 0; k < 8; k++) {
int x = i + dx[k];
int y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'M') {
count++;
}
}
if (count != 0) {
board[i][j] = (char)('0' + count);
return;
} else {
//这个点周围没地雷
board[i][j] = 'B';
for (int k = 0; k < 8; k++) {
int x = i + dx[k];
int y = j + dy[k];
if (x >= 0 && x < m && y >= 0 && y < n && board[x][y] == 'E') {
dfs(board, x, y);
}
}
}
}
}
7. 衣橱整理
7.1 解题思路
这道题是从(0,0)位置开始的,然后记性深度搜索,需深搜过程中需要满足题目中的条件。
7.2 代码实现
java
class Solution {
int[] dx = { 0, 0, -1, 1 };
int[] dy = { -1, 1, 0, 0 };
int count = 0;
int m = 0;
int n = 0;
boolean[][] check;
public int wardrobeFinishing(int _m, int _n, int cnt) {
m = _m;
n = _n;
check = new boolean[m][n];
dfs(0, 0, cnt);
return count;
}
public void dfs(int i, int j, int cnt) {
check[i][j] = true;
count++;
for (int k = 0; k < 4; k++) {
int x = i + dx[k];
int y = j + dy[k];
int sumX = 0;
int sumY = 0;
int tmpX = x;
int tmpY = y;
while (tmpX != 0) {
sumX += tmpX % 10;
tmpX /= 10;
}
while (tmpY != 0) {
sumY += tmpY % 10;
tmpY /= 10;
}
if (x >= 0 && x < m && y >= 0 && y < n &&
check[x][y] == false && sumX + sumY <= cnt) {
dfs(x, y, cnt);
}
}
}
}
8. 记忆化搜索--斐波那契数列
8.1 解题思路
方法一:递归
我们可以直接使用递归的思路来解决这道题,时间复杂度为O(2^n)。
方法二:记忆化搜索算法
我们在利用递归解决问题时候,发现会有好多的重复计算,这时候我们就想到使用一个类似于备忘录的东西,将这些计算过的数据记录在备忘录里面,然后每次进行递归时候就先在备忘录里面进行查询,这样就可以减少重复计算的次数。
方法三:动态规划
我们可以直接使用循环加上备忘录的解法来解决这道题,这道题本质是给你一个数,计算出这个数的斐波那契数,也就是dp[n] = n的斐波那契数。
8.2 代码实现
方法一:
java
class Solution {
public int fib(int n) {
if(n == 0 || n == 1) {
return n;
}
return fib(n-1) + fib(n-2);
}
}
方法二:
java
class Solution {
int[] memo = new int[31];
public int fib(int n) {
//将数组里面数据初始化成-1
Arrays.fill(memo,-1);
return dfs(n);
}
public int dfs(int n) {
//先看数组里面有没
if(memo[n] != -1) {
return memo[n];
}
if(n == 0 || n == 1) {
memo[n] = n;
return n;
}
memo[n] = dfs(n-1) + dfs(n-2);
return memo[n];
}
}
方法三:
java
class Solution {
int[] dp = new int[31];
public int fib(int n) {
dp[0] = 0;
dp[1] = 1;
for(int i = 2; i <= n; i++) {
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
}
9. 不同路径
9.1 解题思路
我们到达一个格子的路径数量 = 到达当前格子的上面格子的路径数量 + 到达当前格子左边格子的路径数量。
方法一:
利用递归的方法,该方法会超出时间限制。
方法二:
利用记忆化搜索方法,利用递归+备忘录。
方法三:
利用动态规划方法,利用循环+备忘录
9.2 代码实现
方法一:
java
class Solution {
public int uniquePaths(int m, int n) {
if(m == 0 || n == 0) {
return 0;
}
if(m == 1 && n == 1) {
return 1;
}
return uniquePaths(m-1,n) + uniquePaths(m,n-1);
}
}
方法二:
java
class Solution {
int[][] memo;
public int uniquePaths(int m, int n) {
memo = new int[m+1][n+1];
return dfs(m,n);
}
public int dfs(int m, int n) {
if(memo[m][n] != 0) {
return memo[m][n];
}
if(m == 0 || n == 0) {
return 0;
}
if(m == 1 && n == 1) {
memo[m][n] = 1;
return memo[m][n];
}
memo[m][n] = dfs(m-1,n) + dfs(m,n-1);
return memo[m][n];
}
}
方法三:
java
class Solution {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m+1][n+1];
dp[1][1] = 1;
for(int i = 1; i < m+1; i++) {
for(int j = 1; j < n+1; j++) {
if(i == 1 && j == 1) {
continue;
}
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m][n];
}
}
10. 最长递增子序列
10.1 解题思路
我们要找到数组的最长递增子序列,需要将数组所有数作为起点开始找最大路径,找一个数为起点的最大递增路径,需要找到下一个数的最大递增路径。
10.2 代码实现
方法一暴力递归:
该方法会超时:
java
class Solution {
public int lengthOfLIS(int[] nums) {
int max = 0;
for(int i = 0; i < nums.length; i++) {
max = Math.max(max,dfs(nums,i));
}
return max;
}
public int dfs(int[] nums, int pos) {
int max = 1;
for(int i = pos + 1; i < nums.length; i++) {
if(nums[i] > nums[pos]) {
max = Math.max(max,dfs(nums,i) + 1);
}
}
return max;
}
}
方法二:
记忆化搜索
java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] memo = new int[n];
int max = 0;
for(int i = 0; i < n; i++) {
max = Math.max(max,dfs(nums,i,memo));
}
return max;
}
public int dfs(int[] nums, int pos,int[] memo) {
if(memo[pos] != 0) {
return memo[pos];
}
int max = 1;
for(int i = pos + 1; i < nums.length; i++) {
if(nums[i] > nums[pos]) {
max = Math.max(max,dfs(nums,i,memo) + 1);
}
}
memo[pos] = max;
return max;
}
}
方法三:
动态规划
java
class Solution {
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
Arrays.fill(dp,1);
int max = 0;
for(int i = n-1; i >= 0; i--) {
for(int j = i + 1; j < n; j++) {
if(nums[j] > nums[i]) {
dp[i] = Math.max(dp[i],dp[j] + 1);
}
}
max = Math.max(max,dp[i]);
}
return max;
}
}
11. 猜数字大小2
11.1 解题思路
这道题让我们就可以猜到数字的最小金额,我们需要把[1,n]之间的每个数字都作为开始遍历一遍,找到这些数字中最小的金额,而每个单独的遍历过程,需要得到左子树和右子树返回的最小金额中的最大值,再加上头节点本身。
如果我们使用暴搜的话,时间会超时,我们可以设置一个二维数组表示在某个区间范围的数的最小现金数。
11.2 代码实现
记忆化搜索代码:
java
class Solution {
int[][] memo;
public int getMoneyAmount(int n) {
memo = new int[n + 1][n + 1];
return dfs(1,n);
}
public int dfs(int x, int y) {
if(x >= y) {
return 0;
}
if(memo[x][y] != 0){
return memo[x][y];
}
int ret = Integer.MAX_VALUE;
for(int i = x; i <= y; i++) {
int n1 = dfs(x,i-1) + i;
int n2 = dfs(i+1,y) + i;
ret = Math.min(Math.max(n1,n2),ret);
}
memo[x][y] = ret;
return ret;
}
}
12. 矩阵中的最长递增路径
12.1 解题思路
这道题我们如果直接暴力搜索的话会超时,因为在递归的过程中会有很多重复的计算,我们可以使用一个二维数组来记录下重复计算的结果。
我们每次递归给一个坐标,然后返回以该坐标为起点的最长递增子数组。
12.2 代码实现
记忆化搜索代码:
java
class Solution {
int[] dx = {0,0,-1,1};
int[] dy = {-1,1,0,0};
int m,n;
int[][] memo;
public int longestIncreasingPath(int[][] matrix) {
m = matrix.length;
n = matrix[0].length;
int max = 0;
memo = new int[m][n];
for(int i = 0; i < m; i++) {
for(int j = 0; j < n; j++) {
//给一个坐标,返回以该坐标为起点的最大值
max = Math.max(dfs(matrix,i,j),max);
}
}
return max;
}
public int dfs(int[][] matrix, int i, int j) {
if(memo[i][j] != 0) {
return memo[i][j];
}
int ret = 1;
for(int k = 0; k < 4; k++) {
int x = i + dx[k];
int y = j + dy[k];
if(x >= 0 && x < m && y >= 0 && y < n &&
matrix[x][y] > matrix[i][j]) {
ret = Math.max(dfs(matrix,x,y)+1,ret);
}
}
memo[i][j] = ret;
return ret;
}
}