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[2i+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的主要内容,如果未能解决你的问题,请参考以下文章