动态规划(自底向上):
338.countingbits(二进制串中有多少个1)
例:如果输入5,应该输出0,1,1,2,1,2
动态规划的最优子结构:f[i] = f[i / 2] + i % 2
647.Palindromic Substrings(求回文子串数量)
例:如果输入aaa,应输出6(a,a,a,aa,aa,aa,aaa)
二维数组dp[i][j]代表从位置i到位置j的子串是否是回文子串
动态规划的最优子结构:dp[i][j] = (s.charAt(i)==s.charAt(j)) && ( j-i<3 || dp[i+1][j-1] )
判断一个字符串是否是回文,首先知道去掉首尾字符的子串是否是回文;
去首尾子串是回文的情况下,若首尾相等则该字符串也为回文
516.Longest Palindromic Substrings(最长回文子序列长度)
例:输入bbbab,输出4(bbbb)
二维数组dp[i][j]代表从位置i到位置到位置j的最长回文子序列长度
动态规划的最优子结构:if(s.charAt(i)==s.charAt(j) && i < j-1) dp[i][j] = dp[i+1][j-1] + 2
计算最长回文子序列时,若首尾相等,则在去掉首位情况下的最长序列的长度加2;
若首尾不等则dp[i][j] = max(dp[i][j-1] ,dp[i+1][j]) 【思路与求回文子串数量相同】
413. Arithmetic Slices(求算术切片数量)
例:输入1,2,3,4,应输出3(123,234,1234)
数组dp[i]代表以第i个元素为结尾的算术切片个数
动态规划的最优子结构:如果A[i] -A[i-1] =A[i-1] - A[i-2],则 dp[i] = dp[i-1]+1;否则dp[i] = 0
646. Maximum Length of Pair Chain(求最长链、贪心)
例:输入[1,2][2,3][3,4],应输出2([1,2][3,4])
本题使用贪心算法更为简便,是活动安排问题的变形
根据第二个元素从小到大排序,后通过一次遍历可得最长链
思路:总是选取当前具有最早完成时间的活动加入链中,可以为为安排的活动留下尽可能多的时间
343.Integer Break(正整数分解求最大积)
例:输入10,应输出36(3*3*4)
数组dp[i]代表正整数i的分解因子相乘的最大积
动态规划最优子结构:dp[i] = max( dp[i], max(j,dp[j]) * max(i-j,dp[i-j]) )
其中j代表i的分解因子,从1到i-1遍历
此题最简便方法是找到3的规律,只要尽可能多的分解出3,即可得到最大积
486.Predict the Winner(从数组两端取数,和最大胜利)
例:输入1,5,199,20,输出true(因为先手可以获得胜利)
二维数组dp[i][j]代表从i位置到j位置进行取数游戏,先手最多比后手多拿多少分数
动态规划最优子结构:dp[i][j]=max( num[i]-dp[i+1][j] , num[j]-dp[i][j-1] )
最终根据dp[0][n-1]的正负来判断是否可以获得胜利
392.Is Subsequence(是否是子序列)
例:输入asjbut、abt,输出true(后者是前者的子序列)
水题,用两个指针遍历即可(不懂为啥放在动态规划一类。。)
650.2 Keys Keyboard(复制粘贴最少次数问题)
例:输入3,输出3(起初只有一个A,要获得三个:1.copy 2.paste 3.paste)
动态规划最优子结构:当i%j==0时,dp[i] = dp[j] + i/j
dp[i]代表获得i个A所需操作的最少次数,指针j从i向1遍历,找到第一个可以被i整除的j
此时获得i个A就在j个A的基础上复制一次,粘贴i/j - 1次,总操作次数为i/j次
416.Partition Equal Subset Sum(能否划分成两个和相等的子集)
例:输入1,2,3,6,输出true(1+2+3=6)
1.(二维数组)动态规划的最优子结构:j>=nums[i]时,dp[i][j] = dp[i-1][j]||dp[i-1][j-nums[i]];否则dp[i][j]=dp[i-1][j]
两层循环:i是1到nums.length-1,j是1到sum/2
dp[i][j]代表,位置i之前的元素是否可以组合产生j;
2.(一维数组)动态规划的最优子结构:j>=nums[i]时,dp[j]=dp[j]||dp[j-sum[i]]
同样是双层循环,i是0到nums.length-1,j是sum/2到1
dp[j]代表,当前位置之前的元素是否可以组合产生j,用一维代替二维,对j的遍历变为从大到小,防止更新dp[j]时用到新的dp[j-sum[i]]
494.Target Sum(给定数组,用加减号连接成式子,结果为S,求有多少种组合)
例:输入[1,1,1,1,1]和3,输出5
数组可分为正负两个子集,正子集和减去负子集和即为S;则可推出正子集和(sum+S)/2,负子集和为(sum-S)/2
即可转化成416题同类型题目(subset sum)
动态规划最优子结构:j>=nums[i]时,dp[j]=dp[j]+dp[j-nums[i]]
312.Burst Balloons(打破气球获得左右和本身乘积,求最大乘积和)【hard】
例:输入[3,1,5,8],输出167(3*1*5+3*5*8+1*3*8+1*8*1=167)假设nums[-1]=nums[n]=1
建立新数组rnums[len+2],即增加头尾俩个1
dp[left][right]代表打破位置left到位置right之间的气球所获得最大乘积,由i在left+1到right-1之间遍历,其中i代表着最后打破的气球序号
动态规划最优子结构:dp[left][right] = Math.max(dp[left][right],rnums[left]*rnums[i]*rnums[right]+dp[left][i]+dp[i][right])
689.Maximum Sum of 3 Non-Overlapping Subarrays(求三个无重叠子数组和的最大值)【hard】
例:输入[1,2,1,2,6,7,5,1]和2,输出[0,3,5](从位置0,3,5起的三个长度为2的子数组和最大)
三个子数组中,第二个数组的起始位置的范围应在k到len-2k之间;
那么第一个数组的结束位置的范围应在k-1到len-2k-1之间,第三个数组的起始位置的范围应在2k到len-k之间;
求出左边的以i为结束的最大k段数组的起始位置,k-1<=i<=len-2k-1;求出右边的以i为起始的最大k段数组的起始位置,2k<=i<=len-k;
最后以i遍历k到len-2k,得到以i-1为结束的最大k段数组的起始位置和以i+k为起始的最大k段数组的起始位置,通过i的遍历取得和的最大值。
377.Combination Sum IV(爬楼梯问题变形)
例:输入[1,2,3]和4,输出7(1111,112,121,13,211,22,31)
用数组onestep存储,一步是否可以达到
dp[target]代表要达到target有多少种方法,当onestep[target-i]为真,dp[target]+=dp[i](考虑最后一步)
198.House Robber(数组不相连元素最大和)
例:输入[1,2,3,4,4],输出8(1+3+4)
水题,动态规划的最优子结构:dp[i] = max(dp[i-1],dp[i-2]+nums[i])
96.Unique Binary Search Trees(独特二叉搜索树的个数)
例:输入3,输出5
水题,动态规划最优子结构:1<j<i-1时,dp[i]+=dp[j]*dp[i-1-j];j=1ori-1时,dp[i]+=dp[i-1]