leetcode之动态规划刷题总结1(Java)

leetcode动态规划刷题总结1

1-最长回文子串
题目链接:题目链接戳这里!!!
在这里插入图片描述
测试了好几次才通过,AC代码如下。
第一次用的暴力枚举,双指针判断回文,超时。
第二次我以为将字符串翻转,和原字符串对比求最长公共子串就可以,其实不是,通过177个测试用例,3个通不过。
第三次,用的动态规划,accept,递推表达式如下:
dp[i][j]=true;
dp[i][j] = dp[i+1][j-1];
就是从i到i的串,也就是单个,一定是回文。
否则,判断左侧i位置的字符是否与右侧j位置的字符相同,若不同,必然不是回文串,若相同,j-i<3,则不超过三个字符,必为回文串,若j-i>=3,则dp[i][j] = dp[i+1][j-1]

public class Solution {
    public static String longestPalindrome(String s) {
        int len = s.length() ;
        if(len==1){
            return s ;
        }
        int max = 1, index=0 ;
        boolean [][]dp = new boolean [len][len] ;
        for(int i=0; i<len; i++){
            dp[i][i] = true ;
        }
        for(int L=2; L<=len; L++){
            for(int i=0; i<len; i++){
                int j = L + i - 1  ;
                if(j>=len){
                    break ;
                }
                if(s.charAt(i) != s.charAt(j)){
                    dp[i][j] = false ;
                }else{
                    if(j-i<3){
                        dp[i][j] = true ;
                    }else{
                        dp[i][j] = dp[i+1][j-1] ;
                    }
                }
                if(dp[i][j] && j-i+1>max){
                    max = j - i + 1;
                    index = i ;
                }
            }
        }
        return s.substring(index, index+max) ;
    }
}

2-括号生成
题目链接:题目链接戳这里!!!
在这里插入图片描述这题用dfs也能AC,搜索根据左右括号剩余数量,添加左括号和右括号,直至剩余个数为0。

class Solution {
   List<String> list = new ArrayList<>() ;
    public List<String> generateParenthesis(int n) {
        dfs(n,n, "") ;
        return list ;
    }
    public  void dfs(int left, int right, String str){
        if(left==0 && right==0){
            list.add(str) ;
            return ;
        }
        if(left>0){
            dfs(left-1, right, str+ "(") ;
        }
        if(right>left){
            dfs(left, right-1, str+ ")") ;
        }
    }
}

动态规划AC代码如下:
递推思想:
“(” + i=p时所有括号的排列组合 +")" + i=q时所有括号的排列组合

import java.util.LinkedList;
import java.util.List;

class Solution {

    public List<String> generateParenthesis(int n) {
        LinkedList <LinkedList<String>> result = new LinkedList<>() ;
        LinkedList<String> list1 = new LinkedList<>() ;
        list1.add("") ;
        LinkedList<String> list2 = new LinkedList<>() ;
        list2.add("()") ;
        result.add(list1) ;
        result.add(list2) ;
        for(int i=2; i<=n; i++){
            LinkedList<String> temp = new LinkedList<>() ;
            for(int j=0; j<i; j++){
                LinkedList<String> str1 = result.get(j) ;
                LinkedList<String> str2 = result.get(i-j-1) ;
                for(String s1 : str1){
                    for(String s2 : str2){
                        String res = "(" + s1 + ")" + s2 ;
                        temp.add(res) ;
                    }
                }
            }
            result.add(temp) ;
        }
        return result.get(n) ;
}
}

3-爬楼梯
题目链接:题目链接戳这里!!!
在这里插入图片描述

水个题,放松一下,AC代码如下:
思想:这题递归也可以做,不过会超时,用简单的递推公式可以,当大于等于3阶楼梯,f[i] = f[i-1] + f[i-2] ,当一阶楼梯f[1]=1,两阶楼梯f[2]=2;

class Solution {
    public int climbStairs(int n) {
        int [] f = new int [n+1] ;

        if(n==1){
            return 1 ;
        }
        if(n == 2){
            return 2 ;
        }
        f[1] = 1 ;
        f[2] = 2 ;
        for(int i=3; i<=n; i++){
            f[i] = f[i-1] + f[i-2] ;
        }
        return f[n] ;
        
    }
}

4-丑数
题目链接:戳这里!!!
三指针法,AC代码如下:
最初三个指针都指向最初位置,依次选择三个指针所在值,乘2,3,5的最小值,依次加入到list中。
在这里插入图片描述

import java.util.List ;
class Solution {
    public int nthUglyNumber(int n) {
        int ans = 1 ;
        if(n==1){
            return 1 ;
        }
        List<Integer> list = new ArrayList<>() ;
        list.add(1) ;
        int idx2 = 0 ;
        int idx3 = 0 ; 
        int idx5 = 0 ;
        for(int i=0; i<n-1; i++){
            int a = list.get(idx2)*2 ;
            int b = list.get(idx3)*3 ;
            int c = list.get(idx5)*5 ;
            int min = Math.min(Math.min(a,b),c) ;
            list.add(min) ;
            if(list.get(list.size()-1) == a){
                idx2 ++ ;
            }
            if(list.get(list.size()-1) == b){
                idx3 ++ ;
            }
            if(list.get(list.size()-1) == c){
                idx5 ++ ;
            }
        }
        return list.get(list.size()-1) ;
    }
}

这样写,更简洁,AC代码如下:
在这里插入图片描述

class Solution {
    public int nthUglyNumber(int n) {
        int idx2=0, idx3=0, idx5=0;
        int [] dp = new int [n] ;
        dp[0] = 1 ;
        for(int i=1; i<n; i++){
            dp[i] = Math.min(2*dp[idx2],Math.min(3*dp[idx3], 5*dp[idx5])) ;
            if(dp[i] == 2 * dp[idx2]){
                idx2++ ;
            }
            if(dp[i] == 3 * dp[idx3]){
                idx3 ++ ;
            }
            if(dp[i] == 5 * dp[idx5]){
                idx5 ++ ;
            }
        }
        return dp[n-1] ;
    }
}

5-杨辉三角
题目链接:题目 链接戳这里!!!
很简单的动态规划,dp[][]的第一行,第一列,最后一列都是1,其余的满足d[i][j] = dp[i-1][j-1]+dp[i-1][j]
AC代码如下:
在这里插入图片描述

class Solution {
    public List<List<Integer>> generate(int numRows) {
        int [][] dp = new int [numRows][numRows] ;
        List<List<Integer>> res = new ArrayList<>() ;
   
        for(int i=0; i<numRows; i++){
            List<Integer> list = new ArrayList<>() ;
            for(int j=0; j<=i; j++){
                if(i==0 || j==0 || i==j){
                    dp[i][j] = 1 ;
                    list.add(dp[i][j]) ;
                }else{
                dp[i][j] = dp[i-1][j-1] + dp[i-1][j] ;
                list.add(dp[i][j]) ;
                }
            }
            res.add(list) ;
        }
        return res ;
    }
}

6-杨辉三角||
题目链接如下:题目链接戳这里!!!
这题和上一题的杨辉三角类似,不再赘述,直接上AC代码
在这里插入图片描述

class Solution {
    public List<Integer> getRow(int rowIndex) {
        List<Integer> list = new ArrayList<>() ;
        int [][]dp = new int [rowIndex+1][rowIndex+1] ;
        for(int i=0; i<=rowIndex; i++){
            for(int j=0; j<=i; j++){
                if(i==0 || j==0 || i==j){
                    dp[i][j] = 1 ;
                }else{
                    dp[i][j] = dp[i-1][j-1] + dp[i-1][j] ;
                }
                if(i==rowIndex){
                    list.add(dp[i][j]) ;
                }
            }
        }
        return  list ;
    }
}

7-最大子数组和
题目链接:题目链接戳这里!!!
这题和最长递增子序列不同,子数组是连续,而子序列不要求连续,每次判断当前的数组值是否大于0,大于0则加到下一个数组上,找到最终数组中的最大值即可。AC代码如下:
在这里插入图片描述

class Solution {
    public int maxSubArray(int[] nums) {
        int max = nums[0] ;
        for(int i=0; i<nums.length-1; i++){
            if(nums[i]>0){
                nums[i+1] += nums[i] ;
            }
          if(nums[i+1] > max){
                max = nums[i+1] ;
            }
        }
        return max ;
    }
}

8-最长递增子序列
递推表达式: dp[i] = Math.max(dp[j]+1, dp[i])
先把dp数组全部填充1,初始化为递增子序列为本身,后面固定i,依次从头遍历j,如果nums[i]>nums[j],则dp[i]变为Math.max(dp[j]+1, dp[i]) ,最后扫描dp数组,找出最大值,就是最长递增子序列的长度。
复杂度O(N^2)
AC代码如下:
在这里插入图片描述

class Solution {
    public int lengthOfLIS(int[] nums) {
        int [] dp = new int [nums.length] ;
        int res = Integer.MIN_VALUE ;
        Arrays.fill(dp, 1) ;
        for(int i=1; i<nums.length; i++){
            for(int j=0; j<i; j++){
                if(nums[i] > nums[j]){
                    dp[i] = Math.max(dp[j]+1, dp[i]) ;
                }
            }
        }
        for(int i=0; i<dp.length; i++){
            res = Math.max(dp[i], res) ;
        }
        return res ;
    }
}

9-完全平方数
题目链接:题目链接戳这里!!!
找到递推公式,就简单了,否则,就很难,这题,用dp数组记录使用的最少的完全平方数,实际上就是背包问题。

思路:dp[n]:表示数字n能由最少由多少个完全平方数求和得到
n是否由n-jj 和 jj凑出
由其凑出:dp[i] = dp[i-j*j]+1
不由其凑出:dp[i] = dp[i]

AC代码如下:
在这里插入图片描述

class Solution {
    public int numSquares(int n) {
        int [] dp = new int [n+1] ;
        Arrays.fill(dp, Integer.MAX_VALUE) ;
        dp[0] = 0 ;
        for(int i=1; i<=n; i++){
            for(int j=1; j*j<=i; j++){
                dp[i] = Math.min(dp[i], dp[i-j*j]+1) ;
            }
        }
        return dp[n] ;
    }
}

10-零钱兑换
题目链接:题目链接戳这里!!!
这题和完全平方数一样,是一个背包问题,AC代码如下:
思路如下:
dp[amount]:表示凑出总金额amount所需的最少硬币数
我们考虑的amount是否由amount-coins凑出,分为凑和不凑两种情况
1-凑:dp[amount] = dp[amount-coins] + 1
2-不凑:dp[amount] = dp[amount]
我们选取二者的最小者即可
在这里插入图片描述

class Solution {
    public int coinChange(int[] coins, int amount) {
        int [] dp = new int [amount + 1] ; 
        Arrays.fill(dp, Integer.MAX_VALUE) ;
        dp[0] = 0 ;
        for(int i=1; i<=amount; i++){
            for(int j=0; j<coins.length; j++){
                if((i-coins[j]>=0) && (dp[i-coins[j]] != Integer.MAX_VALUE)){
                    dp[i] = Math.min(dp[i], dp[i-coins[j]]+1) ;
                }
            }
        }
        if(dp[amount] == Integer.MAX_VALUE){
            return -1 ;
        }
        return dp[amount] ; 
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

nuist__NJUPT

给个鼓励吧,谢谢你

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

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

打赏作者

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

抵扣说明:

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

余额充值