leetcode之动态规划刷题总结3

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之动态规划刷题总结3相关的知识,希望对你有一定的参考价值。

leetcode之动态规划刷题总结3

1-打家劫舍
题目链接:题目链接戳这里!!!

思路:这题思路不难,但是需要注意细节。
递推式:dp[i]=max(dp[i-1],dp[i-2]+nums[i])

class Solution 
    public int rob(int[] nums) 
        if(nums.length==1)
            return nums[0] ;
        
        if(nums.length==2)
            return Math.max(nums[0],nums[1]) ;
        
        int [] dp = new int [nums.length] ;
        dp[0] = nums[0] ;
        dp[1] = Math.max(nums[0],nums[1]) ;
       for(int i=2; i<nums.length; i++)
           dp[i] = Math.max(dp[i-1], nums[i]+dp[i-2]) ;
       
       return dp[nums.length-1];
    


2-打家劫舍II
题目链接:题目链接戳这里!!!

思路:这题与第一题的区别在于防盗系统变成一个环了,递推式还是不变的,只不过第一个和最后一个只能选其一。

class Solution 
    public int rob(int[] nums) 
        if(nums.length==1)
            return nums[0] ;
        
        if(nums.length==2)
            return Math.max(nums[0],nums[1]) ;
        
        return Math.max(f(nums,0,nums.length-1),f(nums,1,nums.length)) ;
    
    public int f(int []nums, int begin, int end)
        int [] dp = new int [end-begin+1] ;
        dp[begin] = nums[begin];
        dp[begin+1] = Math.max(nums[begin],nums[begin+1]) ;
        for(int i=begin+2; i<end; i++)
            dp[i] = Math.max(dp[i-1],dp[i-2]+nums[i]) ;
        
        return dp[end-1] ;
    


3-比特位计数
题目链接:题目链接戳这里!!!

思路:主要式递推式找到,如下所示:
dp[2i] = dp[i] ;
dp[2
i+1] = dp[i]+1;

class Solution 
    public int[] countBits(int n) 
        if(n==0)
            return new int []0 ;
        
        int [] dp = new int [n+1] ;
        dp[0] = 0 ;
        dp[1] = 1 ;
        for(int i=0; i<=n/2; i++)
           dp[2*i] = dp[i] ;
           if(2*i+1<=n)
           dp[2*i+1] = dp[i]+1;
        
        return dp ;
    


4-最佳买卖股票时期含冷冻期
题目链接:题目链接戳这里!!!

思路:sell[i]表示截至第i天,最后一个操作是卖时的最大收益;
buy[i]表示截至第i天,最后一个操作是买时的最大收益;
cool[i]表示截至第i天,最后一个操作是冷冻期时的最大收益;
递推公式:
sell[i] = max(buy[i-1]+prices[i], sell[i-1]) (第一项表示第i天卖出,第二项表示第i天冷冻)
buy[i] = max(cool[i-1]-prices[i], buy[i-1]) (第一项表示第i天买进,第二项表示第i天冷冻)
cool[i] = max(sell[i-1], buy[i-1], cool[i-1])

class Solution 
    public int maxProfit(int[] prices) 
        if(prices.length==1)
            return 0 ;
        
   
       int [] sale = new int [prices.length] ;
       int [] buy = new int [prices.length] ;
       int [] coll = new int [prices.length] ;
       buy[0] = -prices[0] ;
       for(int i=1;i<prices.length; i++)
           sale[i] = Math.max(sale[i-1],buy[i-1]+prices[i]) ;
           buy[i] = Math.max(buy[i-1],coll[i-1]-prices[i]) ;
           coll[i] = Math.max(Math.max(coll[i-1],buy[i-1]),sale[i-1]) ;
       
       return sale[prices.length-1] ;
    


思路2:
f[i][0]:代表持有股票的最大利润
f[i][1]:代表不持有股票,但是处于冷冻期的最大利润
f[i][2]:代表不持有股票,且不处于冷冻期的最大利润

class Solution 
    public int maxProfit(int[] prices) 
        if(prices.length==1)
            return 0 ;
        
        int [][] f = new int [prices.length][3] ;
        f[0][0] = -prices[0] ;
       for(int i=1;i<prices.length; i++)
         f[i][0] = Math.max(f[i-1][0],f[i-1][2]-prices[i]) ;
         f[i][1] = f[i-1][0] + prices[i] ;
         f[i][2] = Math.max(f[i-1][2],f[i-1][1]) ;
       
       return Math.max(f[prices.length-1][1],f[prices.length-1][2]) ;
    


5-为运算表达式设计优先级
题目链接:题目链接戳这里!!!
思路:分治法:如果当前字符串全部为数字,则返回数字即可,不需要运算。
否则需要找出当前的符号,递归计算左半部分和右半部分,再根据符号计算最终结果。

class Solution 
    public List<Integer> diffWaysToCompute(String expression) 
        List<Integer> list = new ArrayList<>() ;
        if(isDigits(expression))
            list.add(Integer.parseInt(expression)) ;
            return list ;
        
        for(int i=0; i<expression.length(); i++)
            if(expression.charAt(i)=='+' || expression.charAt(i)=='-' || expression.charAt(i)=='*')
                List<Integer> left = diffWaysToCompute(expression.substring(0,i)) ;
                List<Integer> right = diffWaysToCompute(expression.substring(i+1)) ;
                char op = expression.charAt(i) ;
                for(int j : left)
                    for(int k : right)
                        if(op=='+')
                            list.add(j+k) ;
                        else if(op=='-')
                            list.add(j-k) ;
                        else if(op=='*')
                            list.add(j*k) ;
                        
                    
                
            
        
        return list ;

    
    public boolean isDigits(String expression)
        for(int i=0; i<expression.length(); i++)
            if(!Character.isDigit(expression.charAt(i)))
                return false ;
             
        
         return true ;
    

6-整数拆分
题目链接:题目链接戳这里!!!

思路:动态规划
dp[i]:表示将正整数i拆分成至少两个正整数和之后,这些正整数的最大乘积。

有两种情况:
第一种,i拆分成i和i-j并且i-j不继续拆分,则当前值为j*(i-j)
第二种,i拆分成i和i-j并且i-j继续拆分,则当前值为j*dp[i-j]

每一轮找出第j个位置拆分的最大值即可。

dp[n]表示将正整数n拆分成至少两个正整数和之后,这些正整数的最大乘积。

class Solution 
    public int integerBreak(int n) 
        int [] dp = new int [n+1] ;
        for(int i=2; i<=n; i++)
            int curMax = 0;
            for(int j=1; j<i; j++)
                curMax = Math.max(curMax,Math.max(j*(i-j),j*dp[i-j])) ;
            
            dp[i] = curMax ;
        
        return dp[n] ;
    


7-计算各个位数不同的数字个数
题目链接:题目链接戳这里!!!

思路1:递归法。
所有位不相同
即第一位9种选择
第二位9种选择(因为多一个0,所有有9种)
第三位8种…接下来依次递减
所有n位数有多少个不同即可获得
在返回count加上小他一位的即可
return count+countNumbersWithUniqueDigits(n-1);

class Solution 
    public int countNumbersWithUniqueDigits(int n) 
        if(n==0)
            return 1 ;
        
        if(n==1)
            return 10 ;
        
        int j = 9 ;
        int cnt = 9 ;
        for(int i=1;i<n; i++)
            cnt *= j ;
            j -- ;
        
        return countNumbersWithUniqueDigits(n-1) + cnt ;
    


思路2:动态规划

class Solution 
    public int countNumbersWithUniqueDigits(int n) 
        if(n==0)
            return 1;
        
      int [] dp = new int [n+1] ;
      dp[0] = 1 ;
      dp[1] = 10;
      for(int i=2; i<=n; i++)
          dp[i] = dp[i-1] + (dp[i-1]-dp[i-2])*(10-(i-1));
      
      return dp[n] ;
    


8-判断子序列
题目链接:题目链接戳这里!!!

思路1:双指针法。

class Solution 
    public boolean isSubsequence(String s, String t) 
        int ls = 0, lt = 0 ;
        while(ls<s.length() && lt<t.length())
            if(s.charAt(ls)==t.charAt(lt))
                ls ++ ;
            
            lt ++ ;
        
        return ls==s.length() ;
    


思路2:调库法,哈哈哈

class Solution 
    public boolean isSubsequence(String s, String t) 
      int idx = -1 ;
      for(char c : s.toCharArray())
          idx = t.indexOf(c,idx+1) ;
          if(idx==-1)
              return false ;
          
      
      return true ;
    


9-等差数列划分
题目链接:题目链接戳这里!!!

思路:规律题。
这道题主要是需要找到其规律,从小的例子出发,仔细观察,会发现当整个数组为(1, 2, 3, 4, 5, 6)的时候,我们先取出前三个,(1, 2, 3)的等差数列的个数为1,(1, 2, 3, 4)的等差数列的个数为3,(1, 2, 3, 4, 5)的等差数列的个数为6,(1, 2, 3, 4, 5, 6)的等差数列个数为10,以此类推我们可以很容易的发现在一个等差数列中加入一个数字,如果还保持着等差数列的特性,每次的增量都会加1,如果刚加进来的数字与原先的序列构不成等差数列,就将增量置为0,接下来继续循环,执行以上的逻辑即可.可以发现,这道题只要找到规律还是相当的简单。

class Solution 
    public int numberOfArithmeticSlices(int[] nums) 
       
        int add = 0 ;
        int res = 0 ;
        for(int i=2; i<nums.length; i++)
            if(nums[i]-nums[i-1]==nums[i-1]-nums[i-2])
                res += (++add) ;
            以上是关于leetcode之动态规划刷题总结3的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode刷题笔记-动态规划-day6

LeetCode刷题笔记-动态规划-day6

leetcode之动态规划刷题总结8

leetcode之动态规划刷题总结6

leetcode之动态规划刷题总结7

leetcode之动态规划刷题总结4