leetcode之记忆化搜索刷题总结1

leetcode之记忆化搜索刷题总结1

1-青蛙跳台阶问题
题目链接:题目链接戳这里!!!

思路1:动态规划思想
f[i]表示跳到第i层的种类数,因为每次可以调一层和二层,故等于跳到第i-1层的种类数+跳到第i-2层的种类数。递推表达式如下:
f[i]=f[i-1]+f[i-2]

class Solution {
    int mod = 1000000007;
    public int numWays(int n) {
       if(n<=1){
           return 1 ;
       }
       int [] f = new int [n+1] ;
       f[0]=f[1] = 1 ;
       for(int i=2; i<=n; i++){
           f[i] = f[i-1]%mod + f[i-2]%mod ;
       }
       return f[n]%mod ;

    }
}

在这里插入图片描述
思路2:记忆化搜索,也就是记忆递归,直接递归由于包含大量重复计算,会超时。

class Solution {
    int mod = 1000000007;
    public int numWays(int n) {
        int [] vis = new int [n+1] ;
        Arrays.fill(vis,-1) ;
        return dfs(vis,n) ;
    }
    public int dfs(int [] vis, int n){
        if(vis[n]!=-1){
            return vis[n] ;
        }
        if(n==0 || n==1){
            return 1 ;
        }
        vis[n] = dfs(vis,n-1)%mod+dfs(vis,n-2)%mod ;
        return vis[n]%mod ;
        
    }
}

在这里插入图片描述
2-三步问题
题目链接:题目据链接戳这里!!!

思路1:动态规划
和上一题思路一样,只不过这一题递推式是三个相加

class Solution {
    int mod = 1000000007 ;
    public int waysToStep(int n) {
        if(n==1){
            return 1 ;
        }else if(n==2){
            return 2 ;
        }else if(n==3){
            return 4 ;
        }
        int [] f = new int [n+1] ;
        f[1]=1;
        f[2]=2;
        f[3]=4;
        for(int i=4; i<=n; i++){
            f[i] = ((f[i-1]%mod + f[i-2]%mod)%mod + f[i-3]%mod)%mod ;
        }
        return f[n]%mod;


    }
}

在这里插入图片描述
思路2:记忆化搜索

class Solution {
    int mod = 1000000007 ;
    public int waysToStep(int n) {
       int [] vis = new int [n+1] ;
       Arrays.fill(vis,-1) ;
       return dfs(vis,n) ;
    }
    public int dfs(int [] vis, int n){
        if(vis[n]!=-1){
            return vis[n] ;
        }
        if(n==1){
            return 1 ;
        }
        if(n==2){
            return 2 ;
        }
        if(n==3){
            return 4 ;
        }
        vis[n] = ((dfs(vis,n-1)%mod + dfs(vis,n-2)%mod)%mod + dfs(vis,n-3)%mod)%mod;
        return vis[n]%mod ;
    }
}

在这里插入图片描述
3-第N个泰波那契数列
题目链接:题目链接戳这里!!!

注意:不是斐波那契数列,哈哈,不过思路一样的,记忆化递归。

class Solution {
    int [] vis ;
    public int tribonacci(int n) {
     vis = new int [n+1] ;
     Arrays.fill(vis,-1) ;
     return dfs(n) ;
    }
    public int dfs(int n){
        if(vis[n]!=-1){
            return vis[n] ;
        }
        if(n==0){
            return 0 ;
        }
        if(n==1 || n==2){
            return 1 ;
        }
        vis[n] =  dfs(n-1) + dfs(n-2) + dfs(n-3) ;
        return vis[n] ;
    }
}

在这里插入图片描述
这题用动态规划也是一样的,不再赘述。

4-斐波那契数列
题目链接:题目链接戳这里!!!

思路:记忆化搜索,动态规划也可以。

class Solution {
    int [] vis ;
    int mod = 1000000007 ;
    public int fib(int n) {
        vis = new int [n+1] ;
        Arrays.fill(vis,-1) ;
        return dfs(n) ;
    }
    public int dfs(int n){
        if(vis[n]!=-1){
            return vis[n] ;
        }
        if(n==0){
            return 0 ;
        }
        if(n==1){
            return 1 ;
        }
        vis[n] = (dfs(n-1)%mod + dfs(n-2)%mod)%mod ;
        return vis[n]%mod ;
    }
}

在这里插入图片描述
5-单词拆分
题目链接:题目链接戳这里!!!

思路1:动态规划
dp[i]表示前i位是否可以用wordDict表示

初始化 dp[0]=true,空字符可以被表示

遍历字符串的所有子串,如果dp[j]为true,则说明前j位可以被wordDict表示,此时若wordDict中存在s.substring(j,i),则dp[i]为true,即前i位可以用wordDict表示。

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        //dp[i]表示前i位是否可以用wordDict表示
        int n = s.length() ;
        boolean [] dp = new boolean [n+1] ;
        dp[0] = true ;
        Set<String> set = new HashSet<>(wordDict) ;
        for(int i=1; i<dp.length; i++){
            for(int j=0; j<i; j++){
                if(dp[j] && set.contains(s.substring(j,i))){
                    dp[i] = true;
                    break ;
                }
            }
        }
        return dp[n] ;
    }
}

在这里插入图片描述

6-矩阵中的最长递增路径
题目链接:题目链接戳这里!!!

思路:沿着四个方向记忆化搜索,每次将搜索到的最大值返回,下次如果在搜索到该位置,直接返回。

class Solution {
    //记忆化搜索
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    int [][] temp ;
    public int longestIncreasingPath(int[][] matrix) {
        int max = Integer.MIN_VALUE ;
        temp = new int [matrix.length][matrix[0].length] ;
        for(int i=0; i<temp.length; i++){
            for(int j=0; j<temp[0].length; j++){
                temp[i][j] = -1 ;
            }
        }
        for(int i=0; i<matrix.length; i++){
            for(int j=0; j<matrix[0].length; j++){
                max = Math.max(max,dfs(matrix,i,j)) ;
            }
        }
        return max ;
    }
    public int dfs(int [][] matrix, int x, int y){
        if(temp[x][y]!=-1){
            return temp[x][y] ;
        }
        temp[x][y] = 1 ;
        int res = 0 ;
        for(int i=0; i<4; i++){
            int tx = x + dx[i] ;
            int ty = y + dy[i] ;
            if(tx<0 || ty<0 || tx>matrix.length-1 || ty>matrix[0].length-1 || matrix[tx][ty]<=matrix[x][y]){
                continue ;
            }
            res = Math.max(res,dfs(matrix,tx,ty)) ;
        }
        temp[x][y] += res ;
        return temp[x][y] ;
    }
}

在这里插入图片描述
这样写看着更舒服,思路是一样的,记忆化搜索

class Solution {
    //记忆化搜索
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    int [][] temp ;
    public int longestIncreasingPath(int[][] matrix) {
        int max = Integer.MIN_VALUE ;
        temp = new int [matrix.length][matrix[0].length] ;
        for(int i=0; i<matrix.length; i++){
            for(int j=0; j<matrix[0].length; j++){
                max = Math.max(max,dfs(matrix,i,j,temp)) ;
            }
        }
        return max ;
    }
    public int dfs(int [][] matrix, int x, int y, int [][] temp){
        if(temp[x][y]!=0){
            return temp[x][y] ;
        }
        temp[x][y] = 1 ;
        int res = 0 ;
        for(int i=0; i<4; i++){
            int tx = x + dx[i] ;
            int ty = y + dy[i] ;
            if(tx>=0 && ty>=0 && tx<=matrix.length-1 && ty<=matrix[0].length-1 && matrix[tx][ty]>matrix[x][y]){
              temp[x][y] = Math.max(temp[x][y],dfs(matrix,tx,ty,temp)+1) ;
            }
        }
        return temp[x][y] ;
    }
}

在这里插入图片描述
7-统计所有可行路径
题目链接:题目链接戳这里!!!

思路:记忆化搜索
我使用数组memo[start][fuel]记录从start开始到finish一共有fuel燃料可以有多少种行驶路径。
最初数组全部填充-1,每次搜索到填充0,对于其它非开始顶点,如果燃料够用,就尝试着走,如果到不了终点,则不可行,达到终点则方案数加1,如果之前已经得到了方案数,下一次则直接返回方案数。

class Solution {
    int [][] memo;
    int mod = 1000000007;
    public int countRoutes(int[] locations, int start, int finish, int fuel) {
        memo = new int [locations.length][fuel+1] ;
        for(int [] arr : memo){
            Arrays.fill(arr,-1) ;
        }
        return dfs(locations,start,finish,fuel) ;
    }
    public int dfs(int [] locations, int start, int finish, int fuel){
        if(memo[start][fuel]!=-1){
            return memo[start][fuel] ;
        }
        memo[start][fuel] = 0 ;
        if(Math.abs(locations[start]-locations[finish]) > fuel){
            return 0 ;
        }
        for(int i=0; i<locations.length; i++){
            if(i!=start){
                int cost ;
                if((cost=Math.abs(locations[start]-locations[i]))<=fuel){
                    memo[start][fuel] += dfs(locations,i,finish,fuel-cost) ;
                    memo[start][fuel] %= mod ;
                }
            }
        }
          if(start==finish){
                memo[start][fuel]++ ;
                memo[start][fuel]%=mod ;
            }
        return memo[start][fuel] ;
    }
}

在这里插入图片描述
8-最长递增路径
题目链接:题目链接戳这里!!!

思路:记忆化搜索,哈哈,这一题竟然重复了,
memo[x][y]是记忆化数组,表示到达当前坐标位置时的最长递增路径长度。从每个点开始,沿着四个方向记忆化搜索,找出每轮搜索找到的最大值,再将所有的最大值进行比较,选出最大的即可。

class Solution {
    int [] dx = {-1,1,0,0} ;
    int [] dy = {0,0,-1,1} ;
    int [][] memo ;
    public int longestIncreasingPath(int[][] matrix) {
        int max = Integer.MIN_VALUE ;
        memo = new int [matrix.length][matrix[0].length] ;
        for(int [] arr : memo){
            Arrays.fill(arr,-1) ;
        }
        for(int i=0; i<matrix.length; i++){
            for(int j=0; j<matrix[0].length; j++){
                max = Math.max(max, dfs(matrix,i,j)) ;
            }
        }
        return max ;
    }
    public int dfs(int [][] matrix, int x, int y){
        if(memo[x][y] != -1){
            return memo[x][y] ;
        }
        memo[x][y] = 1 ;
        for(int i=0; i<4; i++){
            int tx = x + dx[i] ;
            int ty = y + dy[i] ;
            if(tx<0 || ty<0 || tx>matrix.length-1 || ty>matrix[0].length-1 || matrix[tx][ty]<=matrix[x][y]){
                continue ;
            }
            memo[x][y]= Math.max(memo[x][y],dfs(matrix,tx,ty)+1) ;
        }
        return memo[x][y] ;
    }

}

在这里插入图片描述
9-吃掉n个橘子的最少天数
题目链接:题目链接戳这里!!!

思路:记忆化递归
map.get(n)表示吃掉n个橘子所需的最少天数

用f(i)表示吃掉i个橘子所需要的最少天数。
在这里插入图片描述

class Solution {
    Map<Integer, Integer> map = new HashMap<>() ;
    public int minDays(int n) {
        if(n<=1){
            return n ;
        }
        if(map.containsKey(n)){
            return map.get(n) ;
        }
        map.put(n,Math.min(n%2+1+minDays(n/2),n%3+1+minDays(n/3))) ;
        return map.get(n) ;
        
    }
}

在这里插入图片描述
10-有向图中最大颜色值
题目链接:题目链接戳这里!!!

思路:邻接表+dfs+dp
dfs+flag:判断是否成环
dp[i][26]:动态规划记录以i为起点的有效路径中,各颜色的最大值

class Solution {
    char [] color ;
    int [][] dp ;
    int res=0 ;
    public int largestPathValue(String colors, int[][] edges) {
        int [] flag = new int [colors.length()] ;
        dp = new int [colors.length()][26] ;//以i为起点的有效路径中,各颜色的最大值
        color = colors.toCharArray() ; //记录每个点的颜色
        List<List<Integer>> adj = new ArrayList<>() ;
        for(int i=0; i<colors.length(); i++){
            adj.add(new ArrayList<>()) ;
        }  
        for(int [] edge : edges){ //建立邻接表
            adj.get(edge[0]).add(edge[1]) ; 
        }
        for(int i=0; i<colors.length(); i++){
            if(!dfs(adj,i,flag)){
                return -1 ;
            }
        }
        return res ;
    }
    public boolean dfs(List<List<Integer>> adj, int i, int [] flag){
        if(flag[i]==-1){ //上一轮访问过
            return true ;
        }
        if(flag[i]==1){ //有环
            return false ;
        }
        flag[i] = 1 ;
        for(int j : adj.get(i)){
            if(!dfs(adj,j,flag)){
                return false ;
            }
            for(int k=0; k<26; k++){
                dp[i][k] = Math.max(dp[i][k],dp[j][k]) ;
            }
        }
        flag[i] = -1 ;
        dp[i][color[i]-'a'] += 1 ;
        res = Math.max(dp[i][color[i]-'a'],res) ;
        return true ;

    }
}

在这里插入图片描述

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nuist__NJUPT

给个鼓励吧,谢谢你

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值