- 爬楼梯
用dp数组记录到达每个阶梯的方案数
java
class Solution {
public int climbStairs(int n) {
int[] dp=new int[n+1];
dp[0]=1;
dp[1]=1;
for(int i=2;i<=n;i++){
dp[i]=dp[i-1]+dp[i-2];
}
return dp[n];
}
}
- 杨辉三角
模拟,注意头尾为1,中间是按照上一层两个值算出的,只要是算的值,保证加数和被加数存在
java
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> list=new ArrayList<>();
for(int i=0;i<numRows;i++){
List<Integer> temp=new ArrayList<>();
for(int j=0;j<=i;j++){
if(j==0||j==i) temp.add(1);
else temp.add(list.get(i-1).get(j-1)+list.get(i-1).get(j));
}
list.add(temp);
}
return list;
}
}
- 打家劫舍
维护一个当前最大金额
java
class Solution {
public int rob(int[] nums) {
if(nums.length==1) return nums[0];
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],dp[i-2]+nums[i]);
}
return dp[nums.length-1];
}
}
- 完全平方数
java
class Solution {
public int numSquares(int n) {
int[] dp=new int[n+1];
Arrays.fill(dp,10001);
dp[0]=0;
for(int i=1;i<=n;i++){
for(int j=1;j*j<=i;j++){
dp[i]=Math.min(dp[i-j*j]+1,dp[i]);
}
}
return dp[n];
}
}
- 零钱兑换
排序后,如果大于当前值,直接break
初始化为amount+1,可以防止越界(一定记住)
记得dp[0]=0
通过amount+1可以保证,凑不齐时,加到我这里一定不是最小值
java
class Solution {
public int coinChange(int[] coins, int amount) {
Arrays.sort(coins);
int[] dp=new int[amount+1];
Arrays.fill(dp,amount+1);
dp[0]=0;
for(int i=1;i<=amount;i++){
for(int j=0;j<coins.length;j++){
if(coins[j]>i) break;
dp[i]=Math.min(dp[i],dp[i-coins[j]]+1);
}
}
return dp[amount]==amount+1?-1:dp[amount];
}
}
- 单词拆分
从头枚举字符串长度,判断是否存在单词满足该字符串,满足就true,开始下一个字符串
优化点,二重循环枚举字符串头,用set找适合的单词(相比遍历单词数组更快)
java
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
Set<String> set=new HashSet<>();
for(int i=0;i<wordDict.size();i++) set.add(wordDict.get(i));
int n=s.length();
boolean[] dp=new boolean[n+1];
dp[0]=true;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
if(set.contains(s.substring(j-1,i))&&dp[j-1]){
dp[i]=true;
break;
}
}
}
return dp[n];
}
}
- 最长递增子序列
维护一个最长序列
每次大于我最大值,或者为空我直接放在末尾,更新最大值
否则找到第一个大于等于我的值覆盖,方便后续链路找最大值
java
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp=new int[nums.length];
int end=-1;
for(int i=0;i<nums.length;i++){
if(end==-1||dp[end]<nums[i]) dp[++end]=nums[i];
else{
find(nums[i],dp,end);
}
}
return end+1;
}
public void find(int target,int[] dp,int end){
int l=-1,r=end+1;
while(l+1!=r){
int mid=l+(r-l)/2;
int num=dp[mid];
if(num>=target){
r=mid;
}else l=mid;
}
dp[r]=target;
}
}
- 乘积最大子数组
注意动态规划的空间压缩一般是当前状态只依赖前一个状态
java
class Solution {
public int maxProduct(int[] nums) {
int res=nums[0];
int maxVal=nums[0];
int minVal=nums[0];
for(int i=1;i<nums.length;i++){
int max=maxVal;
maxVal=Math.max(nums[i],Math.max(nums[i]*maxVal,nums[i]*minVal));
if(maxVal>res) res=maxVal;
minVal=Math.min(nums[i],Math.min(nums[i]*max,nums[i]*minVal));
}
return res;
}
}
- 分割等和子集
就是找到是否存在子集的和为总和一半
总和为奇数或者最大值大于总和一半直接返回false
找是否存在:用二维dp[i][j](到i值时总和为j的子集是否存在)
java
class Solution {
public boolean canPartition(int[] nums) {
int sum=0;
int max=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
max=Math.max(max,nums[i]);
}
int target=sum/2;
if(sum%2==1||max>target) return false;
boolean[] dp=new boolean[target+1];
dp[0]=true;
for(int i=0;i<nums.length;i++){
for(int j=target;j>=1;j--){
if(j>=nums[i]){
dp[j]|=dp[j-nums[i]];
}
}
}
return dp[target];
}
}
- 最长有效括号
方法一:动态规划
对于dp思路,就两种情况对于')'
1、前一个是(,我只能跟你匹配,但是最长是2+dp[i-2](i>=2)
2、前一个不是(,最长是2+dp[i-1]+dp[i-dp[i-1]-2],并且i-dp[i-1]是(
我的疑问:
为什么不存在dp[i-1]中某个括号和我匹配
因为其中的括号一一对应,没有能跟你组成有效括号的
dp列举的长度,计算时如果是用dp直接算,用s.charAt是索引,还要-1
java
class Solution {
public int longestValidParentheses(String s) {
int cnt=0,n=s.length();
int[] dp=new int[n+1];
for(int i=2;i<=n;i++){
if(s.charAt(i-1)=='(') continue;
if(s.charAt(i-2)=='(') dp[i]=2+dp[i-2];
else{
if(i-dp[i-1]-2>=0&&s.charAt(i-dp[i-1]-2)=='(') dp[i]=2+dp[i-1]+dp[i-dp[i-1]-2];
}
cnt=Math.max(cnt,dp[i]);
}
return cnt;
}
}
考试优先两遍扫描法
java
class Solution {
public int longestValidParentheses(String s) {
int n=s.length(),cnt=0;
int left=0,right=0;
for(int i=0;i<n;i++){
if(s.charAt(i)=='(') left++;
else right++;
if(right==left) cnt=Math.max(cnt,right+left);
if(right>left){
right=0;
left=0;
}
}
right=0;
left=0;
for(int i=n-1;i>=0;i--){
if(s.charAt(i)=='(') left++;
else right++;
if(right==left) cnt=Math.max(cnt,right+left);
if(right<left){
right=0;
left=0;
}
}
return cnt;
}
}