算法---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;
    }
}
相关推荐
苏小瀚2 小时前
算法---二叉树的深搜和回溯
数据结构·算法
诗9趁年华2 小时前
深入分析线程池
java·jvm·算法
九年义务漏网鲨鱼3 小时前
【大模型面经】千问系列专题面经
人工智能·深度学习·算法·大模型·强化学习
源码之家4 小时前
机器学习:基于大数据二手房房价预测与分析系统 可视化 线性回归预测算法 Django框架 链家网站 二手房 计算机毕业设计✅
大数据·算法·机器学习·数据分析·spark·线性回归·推荐算法
Lv Jianwei4 小时前
Longest Palindromic Substring最长回文子串-学习动态规划Dynamic Programming(DP)
算法
WWZZ20254 小时前
快速上手大模型:深度学习7(实践:卷积层)
人工智能·深度学习·算法·机器人·大模型·卷积神经网络·具身智能
l1t5 小时前
用SQL求解advent of code 2024年23题
数据库·sql·算法
10岁的博客5 小时前
二维差分算法高效解靶场问题
java·服务器·算法
轻微的风格艾丝凡5 小时前
锂电池 SOC 估计技术综述:成熟算法、新颖突破与车企应用实践
算法·汽车