算法日志9:动态规划
前言
本篇为动规
斐波那契
动规
class Solution {
public:
//确定dp
//状态转移方程
//dp[i] = dp[i-1]+dp[i-2];
//边界条件
// dp[0] = 0;
// dp[1]= 1
int fib(int n) {
vector<int> dp(n+1);
if(n == 0 || n ==1) return n;
dp[1] = 1;
for(int i= 2; i<=n;i++){
dp[i] = dp[i-1] + dp[i-2];
}
return dp[n];
}
};
递归
class Solution {
public:
int fib(int n) {
if(n == 0 || n==1) return n;
return fib(n-1)+fib(n-2);
}
};
爬楼梯
回溯(会超时)
class Solution {
public:
int res = 0;
void dfs(int n){
if(n == -1){
return;
}
if(n == 0) {
res++;
return;
}
n-=2;
dfs(n);
n+=2;
n-=1;
dfs(n);
n+=1;
}
int climbStairs(int n) {
dfs(n);
return res;
}
};
动规
class Solution {
public:
int climbStairs(int n) {
//状态数组
if(n ==1 || n==2) return n;
vector<int> dp(n+1);
dp[1] = 1;
dp[2] = 2;
for(int i =3; i<=n;i++){
dp[i] = dp[i-1]+dp[i-2];
}
return dp[n];
}
};
使用最小花费爬楼梯
class Solution {
public:
int min(int x, int y){
return x>y?y:x;
}
int minCostClimbingStairs(vector<int>& cost) {
//dp[i] 第i层的花费
//递推公式 dp[i] = min{dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]}
//边界 dp[0] = 0 dp[1]=0
vector<int> dp(cost.size()+1);
dp[0] = dp[1] = 0;
for(int i = 2; i<dp.size();i++){
dp[i] = min(dp[i-1]+cost[i-1], dp[i-2]+cost[i-2]);
}
return dp[dp.size()-1];
}
};
不同路径
class Solution {
public:
int uniquePaths(int m, int n) {
//dp[i][j] = dp[i-1][j]+dp[j-1][i]
vector<vector<int>> dp(m+2, vector<int>(n+2, 0));
dp[0][1] = 1;
for(int i = 1; i<=m;i++){
for(int j =1; j<=n;j++){
dp[i][j] = dp[i-1][j]+dp[i][j-1];
// cout<<dp[i][j]<<" ";
}
}
return dp[m][n];
}
};
不同路径II
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
//dp[i][j] = dp[i-1][j]+dp[j-1][i]
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
vector<vector<int>> dp(m+2, vector<int>(n+2, 0));
dp[0][1] = 1;
for(int i = 1; i<=m;i++){
for(int j =1; j<=n;j++){
if(obstacleGrid[i-1][j-1] == 1){
dp[i][j] = 0;
}
else{
dp[i][j] = dp[i-1][j]+dp[i][j-1];
}
// cout<<dp[i][j]<<" ";
}
}
return dp[m][n];
}
};
整数拆分
class Solution {
public:
int integerBreak(int n) {
// dp[3] = dp[3-1]+1
// 2 = 1+1 =>1
// 3 = 2+1 =1+1+1 =2
// 4 = 3+1 = 2+2 = 4
// 5 = 3+2 = 6
// 6 = 3+3 = 2+4 1+5 = 9
// 7 = 5+2 = 4+3 = 1+6 = 12
// 8 = 1+7 = 2+6= 3+5 =4+4
vector<int> dp(n+1);
dp[1] = 1;
dp[2] = 1;
int max;
for(int i = 3; i<=n;i++){
max = 0;
for(int j = 1; 2*j <= i; j++){
if(max< dp[j] * dp[i-j]) max = dp[j] * dp[i-j];
if(max < j * dp[i-j]) max = j*dp[i-j];
if(max < j * (i-j)) max = j*(i-j);
if(max < dp[j]*(i-j)) max = dp[j] *(i-j);
}
dp[i] = max;
//cout<<"i: "<<i<<" dp[i]: "<<dp[i]<<" ";
}
return dp[n];
}
};
或者
class Solution {
public:
int integerBreak(int n) {
// dp[3] = dp[3-1]+1
// 2 = 1+1 =>1
// 3 = 2+1 =1+1+1 =2
// 4 = 3+1 = 2+2 = 4
// 5 = 3+2 = 6
// 6 = 3+3 = 2+4 1+5 = 9
// 7 = 5+2 = 4+3 = 1+6 = 12
// 8 = 1+7 = 2+6= 3+5 =4+4
vector<int> dp(n+1);
dp[1] = 1;
dp[2] = 1;
int tmp_dp;
for(int i = 3; i<=n;i++){
tmp_dp = 0;
for(int j = 1; 2*j <= i; j++){
int tmp = max({j*dp[i-j], j*(i-j)});
if(tmp > tmp_dp) tmp_dp = tmp;
}
dp[i] = tmp_dp;
//cout<<"i: "<<i<<" dp[i]: "<<dp[i]<<" ";
}
return dp[n];
}
};
不同的二叉搜索树
class Solution {
public:
int numTrees(int n) {
//dp[i]
/*
dp[i]
for dp[j]:dp[0:i]
left: j-1
right: i-j
dp[i] = dp[j-1]*dp[i-j]
*/
vector<int> dp(n+1);
dp[0] = 1;
dp[1]= 1;
for(int i =2;i<=n;i++){
for(int j=1;j<=i;j++){
dp[i]+= dp[j-1]*dp[i-j];
}
}
return dp[n];
}
};
01背包
二维dp数组
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
vector<int> b(m);
vector<int> v(m);
for(int i =0; i<m;i++){
cin>>b[i];
}
for(int i = 0; i<m;i++){
cin>>v[i];
}
//第i个物品的dp[i][0]初始化为0
vector<vector<int>> dp(m, vector<int>(n+1,0));
//第一个物品初始化
for(int i = b[0];i<=n;i++){
dp[0][i] = v[0];
}
//从第二个物品开始遍历, 同时每个物品只需要遍历1~n(即背包大小从1到n),无需遍历0~n
//因为我们在初始化中已经完成了
for(int i = 1; i< m;i++){
for(int j = 1; j<=n; j++){
if(j-b[i] >=0)
dp[i][j] = max(dp[i-1][j], v[i]+dp[i-1][j-b[i]]);
else dp[i][j] = dp[i-1][j];
}
}
cout<<dp[m-1][n]<<endl;
return 0;
}
一维dp数组,加一个辅助数组
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
vector<int> b(m);
vector<int> v(m);
for(int i =0; i<m;i++){
cin>>b[i];
}
for(int i = 0; i<m;i++){
cin>>v[i];
}
//使用一个辅助数组,一个结果数组
vector<int> dp(n+1, 0);
vector<int> tmp(n+1, 0);
for(int i = b[0]; i<=n;i++){
tmp[i] = v[0];
}
for(int i = 1; i<m;i++){
for(int j = 1; j<=n; j++){
if(j - b[i]>=0)
dp[j] = max({tmp[j], tmp[j-b[i]]+v[i]});
else dp[j] = tmp[j];
}
for(int j = 1; j<=n;j++){
tmp[j] = dp[j];
}
}
//这里必须用tmp[n], 因为当物品数量为1个的时候,dp数组没有结果
cout<<tmp[n]<<endl;
return 0;
}
一维dp数组
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
vector<int> b(m);
vector<int> v(m);
for(int i =0; i<m;i++){
cin>>b[i];
}
for(int i = 0; i<m;i++){
cin>>v[i];
}
//一个结果数组
vector<int> dp(n+1, 0);
for(int i = b[0]; i<=n;i++){
dp[i] = v[0];
}
for(int i = 1; i<m;i++){
//必须倒叙,否则存在覆盖的问题,导致在dp过程中无法使用上一层dp的结果
for(int j = n; j>=1; j--){
if(j - b[i]>=0) dp[j] = max({dp[j], dp[j-b[i]]+v[i]});
}
}
cout<<dp[n]<<endl;
return 0;
}
分割等和子集
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
for(auto i: nums){
sum+=i;
}
if((sum/2)*2 != sum) {
cout<<"sum is wrong"<<endl;
return false;
}
int len = nums.size();
vector<int> dp(sum/2+1);
for(int i = nums[0]; i<= sum/2;i++){
dp[i] = nums[0];
}
for(int i = 1; i<len;i++){
for(int j = sum/2; j>=1; j--){
if(j - nums[i]>=0) dp[j] = max(dp[j], nums[i]+dp[j-nums[i]]);
}
}
if(dp[sum/2] == sum/2) return true;
else return false;
}
};
最后一块石头的重量 II
class Solution {
public:
int lastStoneWeightII(vector<int>& stones) {
int sum = 0;
for(auto i: stones){
sum+=i;
}
vector<int> dp(sum/2+1);
for(int i = stones[0]; i<=sum/2;i++){
dp[i] = stones[0];
}
for(int i = 1; i<stones.size();i++){
for(int j = sum/2; j>=1; j--){
if(j - stones[i]>=0)
dp[j] = max({dp[j], stones[i]+dp[j-stones[i]]});
}
}
for(auto i:dp){
cout<<i<<" ";
}
return sum - 2*dp[sum/2];
}
};
目标和
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
int sum = 0;
for(auto i:nums) sum+=i;
if(abs(target) > sum) return 0;
if((target+sum) %2 == 1) return 0;
//len - (sum-len) = target
//2*lem = target+sum
int len = (target+sum)/2;
cout<<"len"<<len<<endl;
vector<int> dp(len+1);
// //初始化第i个物品, 注意和之前的区别,因为是第0件物品,只需要将背包容量nums[0]的置为1
// if(nums[0] <= len) dp[nums[0]] = 1;
// //初始化背包容量为0的情况
// dp[0]=1;
//这是不够的,还需要特判nums[0] 是否等于0
//初始化代码最终为
// if(nums[0] <= len && nums[0] != 0]) dp[nums[0]] = 1;
// if(nums[0] == 0) dp[0] = 2;
// else dp[0] = 1;
//代码可简化为
if(nums[0] <= len) dp[nums[0]] = 1;
dp[0]++;
for(int i = 1; i<nums.size();i++){
for(int j = len; j>=0;j--){
// 物品数量i,背包容量j 的所有情况 = 没有i,背包容量为j + 有i,背包容量j
//没有i: dp[i-1][j]
//有i dp[i-1][j - nums[i]]
// dp[i][j] = 上面两个相加
//特殊情况 j -nums[i] < 0, 此时 dp[i][j] = 没有i
// 经分析,可以用一维dp
// dp[j] = dp[j] + dp[j-nums[i]];
// => dp[j] += dp[j-nums[i]]
if(j - nums[i] >= 0)
dp[j]+=dp[j-nums[i]];
}
//可以简化为
//for(int j = len; j>=nums[i];j--){
// dp[j]+=dp[j-nums[i]];
//}
}
return dp[len];
}
};
//nums[1,2,0,0]
//dp[0][0] = 1; //什么都不选也能填满容量为0的背包,这也是一种方法
//dp[0][1] = 1;
//dp[0][2] = 0;
//dp[1][0] = dp[0][0] = 1 //什么都不选
//dp[1][1] = dp[0][1] = 1
//dp[1][2] = dp[0][2] + dp[0][2-nums[1]] = dp[0][2]+dp[0][0] = 1 // 不选i =1的方法数 + 选i= 1的方法数 = 0 + 1
//dp[2][0] = dp[1][0]+dp[1][0] = 2 //什么都不选填满容量为0 + 选i= 2 v =0 这种情况
//...
//dp[3][0] = dp[2][0]+dp[2][0] = 4 //
//一种特殊情况 nums[0,0]
//dp[0][0] = 1 + 1 //什么都不选 + 选i = 0 v= 2
//dp[0][1] = 0
//dp[1][0] = dp[0][0]*2
//dp[1][1] = dp[0][1] = 0
1和0
class Solution {
public:
int findMaxForm(vector<string>& strs, int m, int n) {
vector<vector<int>> dp(m+1, vector<int>(n+1, 0));
for(auto s : strs){
int sum_0 = 0, sum_1 = 0;
for(auto ss:s){
if(ss == '0') sum_0++;
else sum_1++;
}
for(int i = m; i >= sum_0;i--){
for(int j = n; j>=sum_1;j--){
dp[i][j] = max(dp[i][j], dp[i-sum_0][j-sum_1] + 1);
}
}
}
return dp[m][n];
}
};
完全背包
#include<iostream>
#include<vector>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
vector<int> b(m);
vector<int> v(m);
for(int i = 0; i<m;i++){
cin>>b[i]>>v[i];
}
//初始化,暗含了dp[i][0] = 0
vector<vector<int>> dp(m, vector<int>(n+1,0));
//初始化,能放下0就一直放
for(int i = b[0]; i<=n;i++){
dp[0][i] = dp[0][i - b[0]] + v[0];
}
for(int i = 1; i<m;i++){
for(int j = 1; j<=n;j++){
if(j - b[i]>=0)
dp[i][j] = max(dp[i-1][j], dp[i][j-b[i]]+v[i]);
else dp[i][j] = dp[i-1][j];
}
}
cout<<dp[m-1][n];
return 0;
}
零钱兑换 II
二维数组
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<vector<uint64_t>> dp(coins.size(), vector<uint64_t>(amount+1, 0));
for(int i = coins[0]; i<=amount; i++){
if(i % coins[0] == 0) dp[0][i] = 1;
}
for(int i =0 ; i<coins.size();i++){
dp[i][0] = 1;
}
for(int i = 1; i < coins.size();i++){
for(int j = 1; j<=amount;j++){
if(j - coins[i]>=0)
dp[i][j] = dp[i-1][j]+dp[i][j-coins[i]];
else
dp[i][j] = dp[i-1][j];
}
}
return dp[coins.size()-1][amount];
}
};
一维数组
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<uint64_t> dp(amount+1);
for(int i = coins[0]; i<=amount; i++){
if(i % coins[0] == 0) dp[i] = 1;
}
dp[0] = 1;
for(int i = 1; i < coins.size();i++){
for(int j = coins[i]; j<=amount;j++){
dp[j] +=dp[j-coins[i]];
}
}
return dp[amount];
}
};
组合总数IV
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<uint64_t> dp(target+1);
dp[0] = 1;
for(int i = 0; i <= target;i++){
for(int j = 0; j<nums.size();j++){
if(i-nums[j]>=0)
dp[i] +=dp[i-nums[j]];
}
}
return dp[target];
}
};
爬楼梯(进阶版)
#include<iostream>
#include<vector>
using namespace std;
int main(){
int n,m;
cin>>n>>m;
vector<int> dp(n+1, 0);
dp[0] = 1;
for(int i = 0; i <= n; i++){
for(int j = 0; j< m; j++){
if(i-j-1>=0)
dp[i] += dp[i-(j+1)];
}
}
cout<<dp[n];
return 0;
}
零钱兑换
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1, INT32_MAX);
dp[0] = 0;
for(int i = 0; i<coins.size();i++){
for(int j = coins[i]; j<=amount;j++){
if(dp[j-coins[i]] != INT32_MAX)
dp[j] = min(dp[j], dp[j - coins[i]]+1);
}
}
if(dp[amount] == INT32_MAX) return -1;
return dp[amount];
}
};
完全平方数
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1, INT32_MAX);
int max_item = 1;
for(int i = 1; i<=INT32_MAX; i++){
if(i*i > n){
max_item = i-1;
break;
}
}
dp[0] = 0;
for(int i = 1; i<=max_item; i++){
for(int j = i*i; j<=n;j++){
if(dp[j-(i*i)]!=INT32_MAX)
dp[j] = min(dp[j], dp[j-(i*i)]+1);
}
}
return dp[n];
}
};
单词拆分
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
vector<bool> dp(s.size()+1, 0);
dp[0] = true;
for(int i = 0; i<=s.size(); i++){
for(int j = 0; j < wordDict.size(); j++){
if(i - wordDict[j].size() >= 0 && i - wordDict[j].size()< s.size()){
string word = s.substr(i - wordDict[j].size(), wordDict[j].size());
if(word == wordDict[j] && dp[i - wordDict[j].size()]){
dp[i] = 1;
}
}
}
}
return dp[s.size()];
}
};
多重背包
#include<iostream>
#include<vector>
using namespace std;
int main(){
int m,n;
cin>>m>>n;
vector<int> w(n,0);
vector<int> v(n,0);
vector<int> num(n,0);
for(int i =0; i<n;i++){
cin>>w[i];
}
for(int i =0; i<n;i++){
cin>>v[i];
}
for(int i =0; i<n;i++){
cin>>num[i];
}
vector<int> dp(m+1,0);
for(int i = 0; i<n;i++){
for(int j = m; j>=1; j--){
for(int k = 1; k<=num[i]; k++){
if(j- k*w[i]>=0)
dp[j] = max(dp[j], dp[j-k*w[i]]+k*v[i]);
}
}
}
cout<<dp[m];
}
打家劫舍
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.size() == 1) return nums[0];
if(nums.size()==2) return max(nums[0],nums[1]);
vector<int> dp(nums.size());
dp[0] = nums[0];
dp[1] = max(nums[1],nums[0]);
for(int i = 2; i<nums.size();i++){
dp[i] = max(dp[i-1], dp[i-2]+nums[i]);
}
return dp[nums.size() - 1];
}
};
打家劫舍II
class Solution {
public:
int subrob(vector<int>&nums,int s, int e){
if(e == s) return nums[e];
vector<int> dp(e-s+1, 0);
dp[0] = nums[s];
dp[1] = max(nums[s], nums[s+1]);
for(int i = 2; i <= e-s; i++){
dp[i] = max(dp[i-1], dp[i-2]+nums[i+s]);
}
return dp[e-s];
}
int rob(vector<int>& nums) {
if(nums.size() == 1) return nums[0];
return max(subrob(nums, 0, nums.size()-2), subrob(nums, 1, nums.size()-1));
}
};
打家劫舍III
记忆化递推
class Solution {
public:
unordered_map<TreeNode*, int> res;
int rob(TreeNode* root) {
//边界条件
if(!root) return 0;
if(!root->left&&!root->right) return root->val;
if(res[root]) return res[root];
//单层逻辑
//1.要当前节点,不要左右孩子
int val1 = root->val;
if(root->left) val1+= rob(root->left->left) + rob(root->left->right);
if(root->right) val1+= rob(root->right->left) + rob(root->right->right);
//2. 不要当前节点,要左右孩子
int val2 = rob(root->left)+rob(root->right);
//记录一下当前节点的能取到的最大值,并返回
res[root] = max(val1, val2);
return res[root];
}
};
树型dp
class Solution {
public:
vector<int> dfs(TreeNode* cur){
//res[0]->偷, res[1]->不偷
if(!cur) return {0, 0};
vector<int> res_l = dfs(cur->left);
vector<int> res_r = dfs(cur->right);
int val1 = cur->val + res_l[1] + res_r[1];
int val2 = max(res_l[0], res_l[1])+ max(res_r[0], res_r[1]);
return{val1, val2};
}
int rob(TreeNode* root) {
vector<int> res = dfs(root);
return max(res[0], res[1]);
}
};
买卖股票的最佳时机
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size() == 0) return 0;
vector<vector<int>> dp(prices.size(), vector<int>(2));
//dp[i][0]是持股所得最大利润, dp[i][1]是不持股所得最大利润
dp[0][0] = -prices[0];
dp[0][1] = 0;
for(int i = 1; i<prices.size();i++){
dp[i][0] = max(dp[i-1][0], -prices[i]);
dp[i][1] = max(dp[i-1][1], prices[i]+dp[i-1][0]);
}
return dp[prices.size()-1][1];
}
};
买卖股票的最佳时机 II
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(2));
if(prices.size() == 0) return 0;
dp[0][0] = -prices[0];
dp[0][1] = 0;
for(int i = 1; i<prices.size();i++){
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]);
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]);
}
return dp[prices.size()-1][1];
}
};
空间优化
class Solution {
public:
int maxProfit(vector<int>& prices) {
if(prices.size() == 0) return 0;
int hold = -prices[0];
int un_hold = 0;
for(int i = 1; i<prices.size();i++){
int tmp = hold;
hold = max(hold, un_hold - prices[i]);
un_hold = max(un_hold, tmp + prices[i]);
}
return un_hold;
}
};
买卖股票的最佳时间III
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(4));
dp[0][0] = dp[0][2] = -prices[0];
for(int i =1; i<prices.size();i++){
dp[i][0] = max(dp[i-1][0], -prices[i]);
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]);
dp[i][2] = max(dp[i-1][2], dp[i-1][1]- prices[i]);
dp[i][3] = max(dp[i-1][3], dp[i-1][2]+prices[i]);
}
return dp[prices.size()-1][3];
}
};
买卖股票的最佳时间IV
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(2*k));
for(int i = 0; i<2*k; i+=2){
dp[0][i] = -prices[0];
}
for(int i = 1; i<prices.size(); i++){
dp[i][0] = max(dp[i-1][0], -prices[i]);
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]);
for(int j = 2; j<2*k; j+=2){
dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] - prices[i]);
dp[i][j+1] = max(dp[i-1][j+1], dp[i-1][j]+ prices[i]);
}
}
return dp[prices.size()-1][2*k-1];
}
};
买卖股票的最佳时间(含冷冻期)
打家劫舍思路
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(2));
dp[0][0] = -prices[0];
dp[0][1] = 0;
if(prices.size()>1){
dp[1][0] = max(dp[0][0], dp[0][1] - prices[1]);
dp[1][1]= max(dp[0][1], dp[0][0]+ prices[1]);
for(int i = 2; i<prices.size();i++){
dp[i][0] = max(dp[i-1][0], dp[i-2][1] - prices[i]);
dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]);
}
}
return dp[prices.size()-1][1];
}
};
引入cooling数组
class Solution {
public:
int maxProfit(vector<int>& prices) {
// 0为当前持有能获得的最大利润,1为当前未持有且不在冷冻,2未当前维持有且冷冻
vector<vector<int>> dp(prices.size(), vector<int>(3));
dp[0][0] = -prices[0];
for(int i = 1; i<prices.size(); i++){
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]);
dp[i][1] = max(dp[i-1][1], dp[i-1][2]);
dp[i][2] = dp[i-1][0] + prices[i];
}
return max(dp[prices.size()-1][1], dp[prices.size()-1][2]);
}
};
买卖股票的最佳时间(含手续费)
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
vector<vector<int>> dp(prices.size(), vector<int>(2));
dp[0][0] = -prices[0];
for(int i = 1; i< prices.size();i++){
dp[i][0]=max(dp[i-1][0], dp[i-1][1]-prices[i]);
dp[i][1]=max(dp[i-1][1], dp[i-1][0]+prices[i]-fee);
}
return dp[prices.size()-1][1];
}
};
最长递增子序列
递归(超时)
class Solution {
public:
//递归
int getmax(vector<int>&nums, int cur){
int cur_max = 0;
for(int i = 0; i < cur; i++){
if(nums[i] < nums[cur]) cur_max = max(cur_max, getmax(nums, i));
}
return cur_max+1;
}
int lengthOfLIS(vector<int>& nums) {
int res = 0;
for(int i = 0; i<nums.size();i++){
res = max(res, getmax(nums, i));
}
return res;
}
};
记忆化递归
class Solution {
public:
//记忆化递归
int getmax(vector<int>&nums, vector<int>& memory, int cur){
int cur_max = 0;
for(int i = 0; i < cur; i++){
if(nums[i] < nums[cur]) {
if(memory[i])
cur_max = max(cur_max, memory[i]);
else
cur_max = max(cur_max, getmax(nums,memory, i));
}
}
memory[cur] = cur_max+1;
return cur_max+1;
}
int lengthOfLIS(vector<int>& nums) {
vector<int> memory(nums.size());
int res = 0;
for(int i = 0; i<nums.size();i++){
res = max(res, getmax(nums, memory,i));
}
return res;
}
};
动规
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
//初始化,每个dp[i]至少是1
vector<int> dp(nums.size(),1);
int res = 1;
for(int i =1; i<nums.size();i++){
for(int j = 0; j<i;j++){
if(nums[j] < nums[i]) dp[i] = max(dp[i], dp[j]+1);
}
if(res < dp[i]) res = dp[i];
}
return res;
}
};
单调栈?加二分查找 或者说 贪心加二分查找
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
vector<int> up;
up.push_back(nums[0]);
for(int i = 1; i<nums.size();i++){
auto it = lower_bound(up.begin(), up.end(), nums[i]);
if(it!= up.end()) *it = nums[i];
else up.push_back(nums[i]);
}
return up.size();
}
};
最长连续递增序列
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
//初始化
vector<int> dp(nums.size(),1);
int res = 1;
for(int i = 1; i<nums.size();i++){
if(nums[i-1] < nums[i]) dp[i] = dp[i-1]+1;
if(res< dp[i]) res = dp[i];
}
return res;
}
};
最长重复子数组
class Solution {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
vector<vector<int>> dp(nums1.size()+1, vector<int> (nums2.size()+1));
int res = 0;
for(int i = 1; i<=nums1.size();i++){
for(int j = 1; j<=nums2.size();j++){
if(nums1[i-1] == nums2[j-1]) dp[i][j] = dp[i-1][j-1] +1;
if(dp[i][j]>res) res = dp[i][j];
}
}
return res;
}
};
最长公共子序列
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
vector<vector<int>> dp(text1.size()+1, vector<int>(text2.size()+1, 0));
for(int i= 1; i<=text1.size();i++){
for(int j = 1; j<=text2.size(); j++){
if(text1[i-1] == text2[j-1]){
dp[i][j] = dp[i-1][j-1]+1;
}
else{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
return dp[text1.size()][text2.size()];
}
};
最大子数组和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
//dp[i]是以i为结尾的最大子数组和
vector<int> dp(nums.size());
int res = nums[0];
dp[0] = nums[0];
for(int i = 1; i<nums.size();i++){
dp[i] = max(dp[i-1]+nums[i], nums[i]);
if(dp[i]>res) res = dp[i];
}
return res;
}
};
判断子序列
快慢指针
class Solution {
public:
bool isSubsequence(string s, string t) {
//双指针
if(!s.size() && !t.size()) return true;
if(!s.size()) return true;
if(s.size() && !t.size()) return false;
int fast =0, slow = 0;
while(fast < t.size() && slow < s.size()){
if(t[fast] == s[slow]){
fast++;
slow++;
}
else{
fast++;
}
cout<<"fast:"<<fast<<" slow:"<<slow<<endl;
}
if(slow == s.size()) return true;
else return false;
}
};
动规
class Solution {
public:
bool isSubsequence(string s, string t) {
vector<vector<int>> dp(s.size()+1, vector<int>(t.size()+1));
for(int i = 1; i<= s.size();i++){
for(int j = 1; j<=t.size();j++){
if(s[i-1] == t[j-1]) dp[i][j] = dp[i-1][j-1]+1;
else dp[i][j] = dp[i][j-1];
}
}
if(dp[s.size()][t.size()] == s.size()) return true;
else return false;
}
};
不同的子序列
class Solution {
public:
int numDistinct(string s, string t) {
vector<vector<uint64_t>> dp(s.size()+1, vector<uint64_t>(t.size()+1));
for(int i = 0; i<s.size();i++){
dp[i][0] = 1;
}
for(int i =1 ; i<=s.size();i++){
for(int j = 1; j<=t.size();j++){
if(s[i-1] == t[j-1]) dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
else dp[i][j] = dp[i-1][j];
}
}
return dp[s.size()][t.size()];
}
};
两个字符串的删除操作
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1));
for(int i = 1; i<= word1.size();i++){
dp[i][0] = i;
}
for(int i = 1; i<=word2.size();i++){
dp[0][i] = i;
}
for(int i = 1; i<word1.size()+1; i++){
for(int j = 1; j<=word2.size();j++){
if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = min(dp[i-1][j]+1 ,dp[i][j-1]+1);
}
}
return dp[word1.size()][word2.size()];
}
};
/*
s[i] = ab s[i-1]= a
t[j] = abcc t[j-1] = abc
dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1) = min (3+1, 1+1) = 2
dp[i-1][j-1]+2 = 4
*/
编辑距离
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1));
for(int i = 1; i<=word1.size();i++){
dp[i][0] = i;
}
for(int j = 1; j<=word2.size();j++){
dp[0][j] = j;
}
for(int i = 1; i<=word1.size();i++){
for(int j = 1; j<=word2.size();j++){
if(word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1;
}
}
return dp[word1.size()][word2.size()];
}
};
回文子串
动规
class Solution {
public:
int countSubstrings(string s) {
int res = 0;
vector<vector<bool> > dp(s.size(), vector<bool>(s.size()));
for(int i = s.size()-1; i>=0;i--){
for(int j = i; j<s.size();j++){
if(s[i] == s[j]) {
if(j == i){
dp[i][j] = true;
res++;
}
else if(j-i == 1){
dp[i][j] = true;
res++;
}
else{
dp[i][j] = dp[i+1][j-1];
if(dp[i][j]) res++;
}
}
else dp[i][j] = false;
}
}
return res;
}
};
双指针
class Solution {
public:
int get_s(string &s,int l,int r){
int res = 0;
while(l>=0 && r<s.size()){
if(s[l] == s[r]){
res++;
l--;
r++;
}
else break;
}
return res;
}
int countSubstrings(string s) {
int cnt = 0;
for(int i = 0; i<s.size();i++){
cnt += get_s(s,i,i);
cnt += get_s(s,i,i+1);
}
return cnt;
}
};
最长回文子序列
class Solution {
public:
int longestPalindromeSubseq(string s) {
vector<vector<int>> dp(s.size(), vector<int>(s.size()));
// for(int i =0; i<s.size();i++){
// dp[i][i] = 1;
// }
for(int i = s.size()-1;i>=0;i--){
for(int j = i; j<s.size();j++){
if(s[i] == s[j]) {
if(j-i>=1) dp[i][j] = dp[i+1][j-1]+2;
else dp[i][j] = 1;
}
else dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
}
}
return dp[0][s.size()-1];
}
};
结语
终于结束了

浙公网安备 33010602011771号