算法日志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];
    }
};

结语

终于结束了

posted @ 2025-04-14 17:07  玉米面手雷王  阅读(19)  评论(0)    收藏  举报