注:【LeetCode-面试算法经典】【121-Best Time to Buy and Sell Stock(最佳买卖股票的时间)】这道题记得刷一下
后续还有几个dp问题和解法,比较经典
最大上升子序列
下手角度:
状态方程这样入手,首先,LIS(i)表示的是,以第i个数为结尾的最大上升子序列的长度(这个第i个数一定是这个前i个数中最大上升子序列的最后一个数,也就是必须选取的,以往的都是分成可以选或者不选)
那么
想要知道以i结尾的最大值,就要去找前面比这第i个数小的序列,只要比它大,就+1,当然不止一个,要挑最大的
if(arr[i]>arr[j]
LIS(i)=max(j<i)(LIS[j]+1)
这样最后形成了这样一个数组,每个下表i存储的都是以当前值为结尾的最大上升子序列,因为最大上升子序列的长度必然包含在当前数组中,那么找出这个vector的最大值就是这m个数所构成的最大上升子序列的长度
摆动序列
wiggle subsequence说明
最大上升子序列单纯的就是找到不必相邻的数组主次递增,那么摆动序列呢,就是可以先增再减,也可以先减后增。所以这次设立两个数组
up[i]:同样i还是最后一个元素,它表示的是第i个元素和第i-1个元素的差值是正的(arr[i]-arr[i-1]>0),于是从数组0到n-1每个位置都记录着相对上升子序列
dn[i]:它表示的是第i个元素和第i-1个元素的差值是负的(arr[i]-arr[i-1]<0),于是从数组0到n-1每个位置都记录着相对下降子序列
对于第i位置的元素,先在(0~i-1)找到比arr[i]小的arr[j]下表j,当然有好多个,因为要组成摆动序列,所以这时候要知道位置j的相对下降子序列的长度,
同样对于比arr[i]大的arr[j]下表j,采取相似处理
vetor<int>up(arr.size(),1);vetor<int>dn(arr.size(),1);
if(arr.size()==0)
return 0;
up[0]=dn[0]=1;
for(int i=1;i<n;i++)
{
for(int j=0;j<i;j++)
{
if(arr[i]>arr[j])
{
up[i]=max(up[i],dn[j]+1);
}
if(arr[i]<arr[j])
{
dn[i]=max(dn[i],up[j]+1);
}
}
}
//现在up和dn数组都存储了当前该位置最大的摆动子序列,现在对这两个数组进行遍历,
//找到最大值,最大值即为该位置的最大摆动子序列
int res=0;
for(int i=0;i<n;i++)
{
res=max(res,up[i],dn[i]);
}
return res;
最大公共子序列:
LCS
就是两个字符串,找出最长的相同子串(可以不相邻)
因为是两个字符串,而且长度也不一样,所以可以想到用二维数组搞定
memo[i][j]表示字符串1和字符串2在0~i 和0~j范围内最大长度公共子串,
如果
str[i]==str[j]两个字符串最后以为相同,那么
memo[i][j]=memo[i-1][j-1]+1,就在两个字符串0~i-1和0~j-1找公共字符串,那这些都已经被记录在memo中了
如果两个不等,那么
memo[i][j]=max(memo[i][j-1],memo[i-1][j]);
背包类似问题和相似问题解法
1.leetcode377
combination sum4
给定一个数组,这个数组没有重复的,我想用这几个数来组成我想要的数m,我想知道能有几种方法
这个数组可以是这样的arr={1,2,3,4,5......}这种的,但是每个元素是无限的可以随便取
解法:
很容易想到这个和硬币问题极其相似,只不过这次求的是组合数,有两个限制,一个target数,一个用数字种类,即个数,这就和背包问题相似了
memo[i][j]=memo[i-1][j]+memo[i][j-arr[i]];
解释:首先是用0~i个数来组成j的组合数,这个就和无限拿取的背包问题类似了,只不过这个还涉及了顺序????
解法2
数组arr[i]
求从1~target,每个数可以到达的组合数
vector<int>memo(target-1,0)
for(int i=1;i<=target;i++)
for(int j=0;j<arr.size()-1;j++)
if(i+j<=target)
memo[i+arr[j] ]+=memo[i]+1;
2.leetcode 322
coin change
给定一个面额的数字,最少需要多少硬币来组成这个面额,可以无限次使用,其实这还是一个无限背包问题
memo[i] [j]=memo[i-1] [j];
如果第i个硬币面额比目标面额j小
if(arr[i]<j)
memo[i] [j]=min(memo[i] [j],memo[i] [j-arr[i] ]+1)//状态转移方程
方法2
memo[i]------目标面额i所需要最少的面额
for(int i=1;i<=target;i++)
for(for(int j=0;j<arr.size()-1;j++)
memo[i+arr[j] ]=min(memo[i+arr[j ] ],memo[i]+1)
------------------------------------------------------------------------------------
具体思路和dp问题继续补充
-------------------------------------------------------------------------------------