算法---FloodFill算法和记忆化搜索算法

目录

[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;
    }
}
相关推荐
2401_857918292 分钟前
实时数据处理中的C++应用
开发语言·c++·算法
2401_884563242 分钟前
C++中的装饰器模式实战
开发语言·c++·算法
MicroTech20257 分钟前
微算法科技(NASDAQ :MLGO)抗量子区块链技术:筑牢量子时代的数字安全防线
科技·算法·区块链
Ivanqhz9 分钟前
图着色寄存器分配算法(Graph Coloring)
开发语言·javascript·python·算法·蓝桥杯·rust
Elsa️74611 分钟前
洛谷p5718 复习下快速排序和堆排序
数据结构·算法·排序算法
Frostnova丶13 分钟前
LeetCode 3567.子矩阵的最小绝对差
算法·leetcode·矩阵
夏日听雨眠15 分钟前
文件学习9
数据结构·学习·算法
华农DrLai15 分钟前
什么是自动Prompt优化?为什么需要算法来寻找最佳提示词?
人工智能·算法·llm·nlp·prompt·llama
黎阳之光16 分钟前
十五五智赋新程 黎阳之光以AI硬核技术筑造产业数智底座
大数据·人工智能·算法·安全·数字孪生
2401_8914821717 分钟前
C++中的原型模式
开发语言·c++·算法