LeetCode题解-06(分治、动态规划)


目录
  • LeetCode题解
    • chap-15:分治
        • 1、不同的二叉搜索树 II【卡特兰数】
        • 2、为运算表达式设计优先级
        • 3、从前序与中序遍历序列构造二叉树
        • 4、从中序与后序遍历序列构造二叉树
        • 5、将有序数组转换为二叉搜索树
        • 6、有序链表转换二叉搜索树
    • chap-16:动态规划
      • section16-1: 背包问题
        • 1、01背包 分割等和子集
        • 2、01背包 目标和 【×】
        • 3、完全背包 完全平方数
        • 4、完全背包 零钱兑换
        • 5、完全背包 零钱兑换 II
        • 6、二维背包 一和零
        • 7、求方案数 数位成本和为目标值的最大数字
      • section16-2: LIS模型
        • 1、最长递增子序列
        • 2、俄罗斯套娃信封问题
        • 3、最大整除子集
        • 4、无矛盾的最佳球队
        • 5、堆叠长方体的最大高度
      • section16-3: 线性DP
        • 1、最大子数组和
        • 2、不同路径
        • 3、不同路径 II
        • 4、最小路径和
        • 5、爬楼梯
        • 6、编辑距离 【×】
        • 7、解码方法
        • 8、不同的二叉搜索树
        • 9、交错字符串
        • 10、不同的子序列
        • 11、杨辉三角
        • 12、杨辉三角 II
        • 13、三角形最小路径和
        • 14、分割回文串
        • 15、分割回文串 II【×】
        • 16、地下城游戏【×】
        • 17、最大正方形
        • 18、摆动序列
        • 19、斐波那契数
        • 20、自由之路【×】
        • 21、掷骰子的N种方法
        • 22、带限制的子序列和 【单调队列】
        • 23、跳跃游戏 VI
      • section16-4: 杂选热点DP问题
        • 1、打家劫舍
        • 2、打家劫舍 II
        • 3、摘樱桃 【×】
        • 4、摘樱桃 II 【数字三角形dp】
        • 5、买卖股票的最佳时机 【贪心】
        • 6、买卖股票的最佳时机 II 【状态机】
        • 7、买卖股票的最佳时机 III
        • 8、买卖股票的最佳时机 IV 【状态机】
        • 9、最佳买卖股票时机含冷冻期【状态机】
        • 10、买卖股票的最佳时机含手续费【状态机】
        • 11、正则表达式匹配 【×】
        • 12、通配符匹配
        • 23、跳跃游戏 VI
      • section16-5: 区间DP
        • 1、戳气球
        • 2、猜数字大小 II
        • 3、预测赢家
        • 4、最长回文子序列
        • 5、统计不同回文子序列 【×】区间dp+双端队列
        • 6、石子游戏 【思路同题3】
        • 7、石子游戏 VII
      • section16-6: 记忆化搜索
        • 1、【树形dp】打家劫舍 III
        • 2、分发糖果
        • 3、矩阵中的最长递增路径 【对应-滑雪acwing】
        • 4、我能赢吗 【×】
        • 5、猫和老鼠
      • section16-7: 状态机dp+状压dp
        • 1、最佳买卖股票时机含冷冻期
        • 2、学生出勤记录 II
        • 3、买卖股票的最佳时机含手续费
        • 4、我能赢吗 【×】

LeetCode题解

chap-15:分治

1、不同的二叉搜索树 II【卡特兰数】

class Solution {
public:
    vector generateTrees(int n) {
        return dfs(1,n);
    }

    vector dfs(int l,int r){
        if(l>r) return{nullptr};
        vector res; 
        for(int i = l;i<=r;i++){
            auto left = dfs(l,i-1),right = dfs(i+1,r);
            for(auto &l:left){
                for(auto &r:right){
                    auto root = new TreeNode(i);
                    root->left = l;
                    root->right = r;
                    res.push_back(root);
                }
            }
        }
        return res;
    }
};

2、为运算表达式设计优先级

class Solution {
public:
    vector diffWaysToCompute(string ep) {
        vector ans;
        for(int i=0;i{stoi(ep)}:ans;
    }
};

3、从前序与中序遍历序列构造二叉树

class Solution {
public:
    unordered_map hash;
    TreeNode* buildTree(vector& pre, vector& in) {
        for(int i=0;i&pre, vector&in, int pl,int pr,int il,int ir){
        if(pl>pr) return nullptr;
        auto root = new TreeNode(pre[pl]);
        int i = hash[root->val];
        root->left = dfs(pre,in,pl+1,i-il+pl,il,i-1);
        root->right = dfs(pre,in,i-il+pl+1,pr,i+1,ir);
        return root;
    }
};

4、从中序与后序遍历序列构造二叉树

class Solution {
public:
    unordered_map pos;
    TreeNode* buildTree(vector& inorder, vector& postorder) {
        for (int i = 0; i < inorder.size(); i ++ ) pos[inorder[i]] = i;
        return build(inorder, postorder, 0, inorder.size() - 1, 0, postorder.size() - 1);
    }
    TreeNode* build(vector& inorder, vector& postorder, int il, int ir, int pl, int pr) {
        if (il > ir) return NULL;
        auto root = new TreeNode(postorder[pr]);
        int k = pos[root->val];
        root->left = build(inorder, postorder, il, k - 1, pl, pl + k - 1 - il);
        root->right = build(inorder, postorder, k + 1, ir, pl + k - 1 - il + 1, pr - 1);
        return root;
    }
};

5、将有序数组转换为二叉搜索树

class Solution {
public:
    TreeNode* sortedArrayToBST(vector& nums) {
        return dfs(0,nums.size()-1,nums);
    }
    TreeNode* dfs(int l, int r, vector&nums){
        if(l>r) return nullptr;
        int mid=l+r>>1;
        auto root = new TreeNode(nums[mid]);
        root->left = dfs(l,mid-1,nums);
        root->right = dfs(mid+1,r,nums);
        return root;
    }
};

6、有序链表转换二叉搜索树

class Solution {
public:
    TreeNode* sortedListToBST(ListNode* head) {
        if(head == nullptr) return nullptr;
        int n=0;
        for(auto p = head;p;p = p->next) n++;
        if(n == 1) return new TreeNode(head->val);
        auto cur = head;
        for(int i =0;inext;
        }
        auto t = new TreeNode(cur->next->val);
        t->right = sortedListToBST(cur->next->next);
        cur->next = nullptr;
        t->left = sortedListToBST(head);
        return t;
    }
};

[Go Back~](# LeetCode题解)

chap-16:动态规划

section16-1: 背包问题

1、01背包 分割等和子集

class Solution {
public:
    bool canPartition(vector& nums) {
        int sum=accumulate(nums.begin(),nums.end(),0);
        if(sum%2) return false;
        sum/=2; vectorf(sum+1,false); f[0]=true;
        for(auto &n:nums){
            for(int i=sum;i>=n;i--)
                f[i] = f[i]|f[i-n];
            if(f[sum]) return true;
        }
        return f[sum];
    }
};

2、01背包 目标和 【×】

class Solution {
public:
    int findTargetSumWays(vector& nums, int target) {
        int offset=accumulate(nums.begin(),nums.end(),0);
        offset = max(abs(target), offset);
        int n=nums.size();
        vector> f(n+1,vector(2*offset+1,0));
        f[0][offset+0]=1;
        for(int i=1;i<=n;i++){
            for(int j=offset;j>=-offset;j--){
                if(j-nums[i-1]>=-offset)
                    f[i][j+offset] += f[i-1][j-nums[i-1]+offset] ;
                if(j+nums[i-1]<=offset)
                    f[i][j+offset] += f[i-1][j+nums[i-1]+offset] ;
            }
        }
        return f[n][target+offset];
    }
};

3、完全背包 完全平方数

class Solution {
public:
    int numSquares(int n) {
        vector f(n+1,INT_MAX); f[0]=0;
        for(int i=1;i*i<=n;i++){
            int t = i*i;
            for(int j=t;j<=n;j++)
                f[j] = min(f[j], f[j-t]+1);
        }
        return f[n];
    }
};

4、完全背包 零钱兑换

class Solution {
public:
    int coinChange(vector& coins, int m) {
        int n = coins.size();
        sort(coins.begin(),coins.end());
        vector f(m+1,0x3f3f3f3f);
        f[0] = 0;
        for(int i = 1;i<=m;i++){
            for(int j = n-1;j>=0;j--){   
                if(i - coins[j] >= 0)             
                    f[i] = min(f[i - coins[j]] + 1,f[i]);
            }
        }
        return f[m] == 0x3f3f3f3f ? -1 : f[m];
    }
};

5、完全背包 零钱兑换 II

class Solution {
public:
    int change(int amount, vector& coins) {
        vector f(amount+1,0);
        f[0]=1;
        for(auto &coin : coins){
            for(int i=coin;i<=amount;i++)
                f[i] += f[i-coin];
        }
        return f[amount];
    }
};

6、二维背包 一和零

class Solution {
public:
    int findMaxForm(vector& strs, int m, int n) {
        vector>f(m+1,vector(n+1,0));
        for(auto &s:strs){
            int cnt0=0,cnt1=0;
            for(auto &c:s) if(c=='0') cnt0++; else cnt1++;
            for(int i=m;i>=cnt0;i--)
                for(int j=n;j>=cnt1;j--)
                    f[i][j] = max(f[i][j], f[i-cnt0][j-cnt1]+1);
        }
        return f[m][n];
    }
};

7、求方案数 数位成本和为目标值的最大数字

class Solution {
public:
    string largestNumber(vector& cost, int target) {
        vector f(target+1,INT_MIN);
        f[0]=0;
        for(int i=0;i= 0; i--) {
            while (j >= cost[i] && f[j] == f[j - cost[i]] + 1) {
                ans += to_string(i + 1);
                j -= cost[i];
            }
        }
        return ans;
    }
};

[Go Back~](# LeetCode题解)

section16-2: LIS模型

1、最长递增子序列

class Solution {
public:
    int lengthOfLIS(vector& nums) {
        vector dp(nums.size(),1); // O(n^2)
        int res = 1;
        for(int i= 1;inums[j])
                    dp[i] = max(dp[i],dp[j]+1);
            }
            res = max(dp[i], res);
        }
        return res;
    }
};

// O(nlog(n))
class Solution {
public:
    int lengthOfLIS(vector& nums) {
        int n=nums.size(), len=1;
        vector f(n+1,0);
        f[len]=nums[0];
        for(int i=1;i<=n;i++){
            int l=1, r=len;
            while(l<=r){
                int mid=l+r>>1;
                if(f[mid] < nums[i-1]) l = mid+1;
                else r=mid-1;
            }
            if(l>len) len++; f[l]=nums[i-1];
        }
        return len;
    }
};

2、俄罗斯套娃信封问题

class Solution {
public:
    int maxEnvelopes(vector>& envelopes) {
        int n = envelopes.size();
        sort(envelopes.begin(),envelopes.end());
        vector f(n+1,1);
        int ans=0;
        for(int i=1;i<=n;i++){
            int w=envelopes[i-1][0], h=envelopes[i-1][1];
            for(int j=1;j

3、最大整除子集

class Solution {
public:
    vector largestDivisibleSubset(vector& nums) {
        sort(nums.begin(), nums.end());
        vector f(nums.size()+1,0);
        int t=0;
        for(int i=1;i<=nums.size();i++){
            f[i]=1;
            for(int j=1;j ans;
        for(int j=nums.size();j>=1;j--){
            if(t == f[j]){
                if(ans.empty()) t--,ans.push_back(nums[j-1]);
                else if(ans.back() % nums[j-1] == 0)
                     t--,ans.push_back(nums[j-1]);
            }
        }
        return ans;
    }
};

4、无矛盾的最佳球队

class Solution {
public:
    int bestTeamScore(vector& scores, vector& ages) {
        int n=scores.size(); vector rank(n);
        for(int i=0;i f(n+1); int ans=0;
        for (int i = 0; i < n; i++) {
            f[i] = scores[rank[i]];
            for (int j = 0; j < i; j++)
                if (ages[rank[j]] <= ages[rank[i]])
                    f[i] = max(f[i], f[j] + scores[rank[i]]);

            ans = max(ans, f[i]);
        }
        return ans;
    }
};

5、堆叠长方体的最大高度

class Solution {
public:
    int maxHeight(vector>& cuboids) {
        for(auto &cuboid:cuboids){
            sort(cuboid.begin(),cuboid.end());
        }
        sort(cuboids.begin(),cuboids.end());
        vector f(cuboids.size(),0);
        int ans=0;
        for(int i=0;i

[Go Back~](# LeetCode题解)

section16-3: 线性DP

1、最大子数组和

class Solution {
public:
    int maxSubArray(vector& nums) {
        int sum = 0,ans = -0x3f3f3f3f;
        for(auto &item:nums){
            sum += item;
            ans = max(sum,ans);
            if(sum < 0) sum = 0;
        }
        return ans;
    }
};

2、不同路径

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector f(n+1,0);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++){
                if(i==1&&j==1) f[j]=1;
                else f[j] = f[j] + f[j-1];
            }
        return f[n];
    }
};

3、不同路径 II

class Solution {
public:
    int uniquePathsWithObstacles(vector>& w) {
        int n=w.size(), m=w[0].size();
        if(w[0][0] || w[n-1][m-1]) return 0;
        vector> f(n+1,vector(m+1,0));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(i==1 && j==1) f[i][j]=1;
                else if(!w[i-1][j-1]) f[i][j]=f[i-1][j]+f[i][j-1];
        return f[n][m];
    }
};

4、最小路径和

class Solution {
public:
    int minPathSum(vector>& grid) {
        int n=grid.size(), m=grid[0].size();        
        vectorf(m+1,0x3f3f3f3f);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
                if(i==1 && j==1) f[j]=grid[i-1][j-1];
                else f[j] = min(f[j], f[j-1]) + grid[i-1][j-1];
        }
        return f[m];
    }
};

5、爬楼梯

class Solution {
public:
    int climbStairs(int n) {
        vector f(n+1); f[0]=1, f[1]=1;
        for(int i=2;i<=n;i++)
            f[i] = f[i-1]+f[i-2];
        return f[n];
    }
};

class Solution {
public:
    int climbStairs(int n) {
        int a=1, b=1, c;
        for(int i=2;i<=n;i++){
            c = a+b; a = b; b = c;
        }
        return b;
    }
};

6、编辑距离 【×】

class Solution {
public:
    int minDistance(string word1, string word2) {
        int n=word1.size(), m=word2.size();
        word1 = ' '+word1;
        word2 = ' '+word2;
        vector> f(n+1,vector(m+1,0x3f3f3f));
        for (int i = 0; i <= n; i ++ ) f[i][0] = i;
        for (int i = 1; i <= m; i ++ ) f[0][i] = i;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(word2[j] == word1[i])
                    f[i][j] = min(f[i-1][j-1], f[i][j]);
                else
                    f[i][j] = min(f[i-1][j-1]+1, min(f[i-1][j]+1, f[i][j-1]+1));
            }
        }
        return f[n][m];
    }
};

7、解码方法

class Solution {
public:
    int numDecodings(string s) {
        int n=s.size();
        vector f(n+1,0);
        s = ' '+s;
        f[0]=1;
        for(int i=1;i<=n;i++){
            if(i==1) {if(s[i] != '0') f[i]=1;}
            else {   
                string t; t+=s[i-1]; t+=s[i];
                int a = stoi(t);
                if(s[i] != '0'){
                    f[i] = f[i-1];
                    if(a>=10 && a<=26) f[i] = f[i]+f[i-2];
                }else{
                    if(a == 10 || a == 20)
                        f[i] = f[i-2];
                }
            }
        }
        return f[n];
    }
};

8、不同的二叉搜索树

class Solution {
public:
    int numTrees(int n) {
        vectorf(n+1,0);
        f[0]=1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=i;j++)
                f[i] += f[i-j]*f[j-1];
        return f[n];
    }
};

9、交错字符串

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        int n1 = s1.size(), n2 = s2.size(), n = s3.size();
        if((n1+n2) != n) return false;
        vector> f(n1+1,vector(n2+1, false));
        s1 = ' '+s1; s2 = ' '+s2; s3 = ' '+s3;
        for(int j=0;j<=n1;j++)
            for(int i=0;i<=n2;i++){
                if(!i && !j) f[j][i] = 1;
                else{
                    if(j && s1[j] == s3[i+j]) f[j][i] = f[j-1][i];
                    if(i && s2[i] == s3[i+j]) f[j][i] = f[j][i] || f[j][i-1];
                }
            }
        return f[n1][n2];
    }
};

10、不同的子序列

class Solution {
public:
    int numDistinct(string s, string t) {
        int n=s.size(),m=t.size();
        s = ' '+s; t = ' '+t;
        vector>f(m+1,vector(n+1,0));
        for(int i=0;i<=n;i++) f[0][i]=1;
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++){
                if(s[j] != t[i]) f[i][j] = f[i][j-1];
                else f[i][j] = f[i-1][j-1]+f[i][j-1];
            }
        return f[m][n];
    }
};

11、杨辉三角

class Solution {
public:
    vector> generate(int numRows) {
        vector> ans;
        for(int i=1;i<=numRows;i++){
            if(ans.empty()) ans.push_back({1});
            else{
                vector t; t.push_back(1);
                for(int j=2;j<=i;j++){
                    if(j>ans.back().size()) t.push_back(1);
                    else{
                        t.push_back(ans.back()[j-2]+ans.back()[j-1]);
                    }
                }
                ans.push_back(t);
            }
        }
        return ans;
    }
};

12、杨辉三角 II

class Solution {
public:
    vector getRow(int rowIndex) {
        vector ans(rowIndex+1,0);
        for(int i=0;i<=rowIndex;i++){
            for(int j=i;j>=0;j--){
                if(!j) ans[j] = 1;
                else{
                    if(j < i) ans[j] = ans[j-1] + ans[j];
                    else ans[j] = ans[j-1] + 0;
                }
            }
        }
        return ans;
    }
};

13、三角形最小路径和

class Solution {
public:
    int minimumTotal(vector>& dp) {
        for(int i = dp.size() - 2;i>=0;i--){
            for(int j = 0;j

14、分割回文串

class Solution {
public:
    vector> f;
    vector> res;
    vector> partition(string s) {
        int n=s.size();
        f = vector>(n,vector(n,false));
        f[0][0]=1;
        for(int i=1;i path;
        dfs(s,0,path);
        return res;
    }
    void dfs(string&s, int u,vector path){
        if(u == s.size()) res.push_back(path);
        else{
            for(int i=u;i

15、分割回文串 II【×】

class Solution {
public:
    int minCut(string s) {
        int n = s.size();
        vector>f(n,vector(n,false));
        f[0][0]=1;
        for(int i=1;i dp(n+1,INT_MAX);
        dp[0]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j

16、地下城游戏【×】

class Solution {
public:
    int calculateMinimumHP(vector>& dungeon) {
        int n=dungeon.size(), m=dungeon[0].size();
        vector> f(n+1,vector(m+1,0x3f3f3f));
        f[n][m-1]=1, f[n-1][m]=1;
        for(int i=n-1;i>=0;i--){
            for(int j=m-1;j>=0;j--){
                f[i][j] = max(1,min(f[i+1][j],f[i][j+1])-dungeon[i][j]);
            }
        }
        return f[0][0];
    }
};

17、最大正方形

class Solution {
public:
    int maximalSquare(vector>& matrix) {
        int n = matrix.size(), m = matrix[0].size();
        vector> f(n+1,vector(m+1));
        int res = 0;
        for(int i = 1;i<=n;i++){
            for(int j = 1;j<=m;j++){
                if(matrix[i-1][j-1] == '0') f[i][j] = 0;
                else{
                    f[i][j] = min(f[i-1][j-1],min(f[i-1][j],f[i][j-1])) + 1;
                    res = max(res,f[i][j]);
                }
            }
        }
        return res * res;
    }
};

18、摆动序列

class Solution {
public:
    int wiggleMaxLength(vector& nums) {
        int n=nums.size();
        vector f1(n,0); //上升序列
        vector f0(n,0); //下沉序列
        f0[0]=f1[0]=1;
        for(int i=1;inums[i-1]){
                f1[i]=f0[i-1]+1;
                f0[i]=f0[i-1];
            }else if(nums[i]

19、斐波那契数

class Solution {
public:
    int fib(int n) {
        if(!n) return 0;
        vector f(n+1,0);
        f[0]=0, f[1]=1;
        for(int i=2;i<=n;i++) f[i]=f[i-1]+f[i-2];
        return f[n];
    }
};

class Solution {
public:
    int fib(int n) {
        if(!n) return 0;        
        int c=0, a=0, b=1;
        for(int i=2;i<=n;i++) {
            c=a+b;
            a = b;
            b = c;
        }
        return b;
    }
};

20、自由之路【×】

class Solution {
public:
    int findRotateSteps(string ring, string key) {
        int n=ring.size(), m=key.size();
        vector> f(m,vector(n,0x3f3f3f));
        for(int i=0;i

21、掷骰子的N种方法

class Solution {
public:
    int numRollsToTarget(int n, int k, int target) {
        const int mod = 1e9 + 7;
        vector>f(n+1,vector(target+1,0));
        f[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=k;j++){
                for(int t=j;t<=target;t++)
                    f[i][t] = (f[i][t] + f[i-1][t-j])%mod;
            }
        }
        return f[n][target];
    }
};

22、带限制的子序列和 【单调队列】

class Solution {
public:
    int constrainedSubsetSum(vector& nums, int k) {
        int n=nums.size();
        vector f(n,0);
        f[0]=nums[0]; 
        int ans=nums[0];
        deque q; 
        q.push_back(0);

        for(int i=1;ik) q.pop_front();
            f[i] = max(0, f[q.front()]) + nums[i];
            
            ans = max(f[i], ans);
            while(q.size() && f[i] >= f[q.back()]) q.pop_back();
            q.push_back(i);
        }
        return ans;
    }
};

23、跳跃游戏 VI

class Solution {
public:
    int maxResult(vector& nums, int k) {
        int n=nums.size();
        vector f(n,0); f[0]=nums[0];
        deque q; q.push_back(0);
        for(int i=1;ik) q.pop_front();
            f[i] = f[q.front()] + nums[i];
            while(q.size() && f[i] >= f[q.back()]) q.pop_back();
            q.push_back(i);
        }
        return f[n-1];
    }
};

[Go Back~](# LeetCode题解)

section16-4: 杂选热点DP问题

1、打家劫舍

class Solution {
public:
    int rob(vector& nums) {
        int n=nums.size();
        vector f(n+1,0);
        for(int i=1;i<=n;i++){
            if(i==1) f[i] = max(f[i-1], nums[i-1]);
            else f[i] = max(f[i-1], f[i-2]+nums[i-1]);
        }
        return f[n];
    }
};

2、打家劫舍 II

class Solution {
public:
    int rob(vector& nums) {
        int n=nums.size(), ans=0;
        vector f(n+1,0);
        for(int i=n-1;i>=0;i--){
            // 第一个不取,最后一个取
            if(i==n-1)  f[i] = nums[i];
            else if(i == 0) f[i] = f[i+1];
            else f[i] = max(f[i+1], f[i+2]+nums[i]);
        }
        ans = max(ans, f[0]);
        f = vector(n+1,0);
        for(int i=1;i<=n;i++){
            // 第一个取,最后一个不取
            if(i==1) f[i] = nums[i-1];
            else if(i == n) f[i] = f[i-1];
            else f[i] = max(f[i-1], f[i-2]+nums[i-1]);
        }
        ans = max(ans,f[n]);
        return ans;
    }
};

3、摘樱桃 【×】

class Solution {
public:
    int cherryPickup(vector>& grid) {
        int n=grid.size();
        vector>> f(2*n,vector>(n,vector(n,-0x3f3f3f)));
        f[0][0][0] = grid[0][0];
        for(int k=1;k<=2*n-2;k++){
            for(int i1=0;i1= n || j2 < 0 || j2 >= n) continue; //越界
                    if(grid[i1][j1]==-1 || grid[i2][j2] == -1) continue;
                    int t = grid[i1][j1]; //取得该格子
                    if (i1 != i2) t += grid[i2][j2]; //没有重合
                    int &x = f[k][i1][i2];
                    x = max(x, f[k - 1][i1][i2] + t);
                    if(i1) x = max(x, f[k-1][i1-1][i2] + t);
                    if(i2) x = max(x, f[k-1][i1][i2-1] + t);
                    if(i1 && i2) x = max(x, f[k-1][i1-1][i2-1] + t);
                }
            }            
        }
        return max(0,f[2*n-2][n-1][n-1]);
    }
};

4、摘樱桃 II 【数字三角形dp】

class Solution {
public:
    int cherryPickup(vector>& grid) {
        int n = grid.size(), m = grid[0].size();
        vector>> f(n, vector> (m, vector (m, -1)));

        f[0][0][m - 1] = grid[0][0] + grid[0][m - 1]; //开始状态

        int res = 0;
        for (int k = 1; k < n; k ++) //从第二行开始循环
            for (int i = 0; i < m; i ++) 
                for (int j = 0; j < m; j ++)

                    for (int a = i - 1; a <= i + 1; a ++) // 可能情况枚举
                        for (int b = j - 1; b <= j + 1; b ++)
                        {
                            if (a < 0 || a >= m || b < 0 || b >= m) continue; //越界
                            int t = f[k - 1][a][b];
                            if (t < 0) continue; //不合法

                            if (i == j) f[k][i][j] = max(f[k][i][j], t + grid[k][i]); //重合时只算一次分值
                            else f[k][i][j] = max(f[k][i][j], t + grid[k][i] + grid[k][j]);
                            res = max(res, f[k][i][j]);
                        }

        return res;
    }
};

5、买卖股票的最佳时机 【贪心】

class Solution {
public:
    int maxProfit(vector& prices) {
        int minp = prices[0], ans = 0;
        for(int i=1;i

6、买卖股票的最佳时机 II 【状态机】

class Solution {
public:
    int maxProfit(vector& prices) {
        int n=prices.size();
        int f[n][2]; f[0][0] = 0, f[0][1] = -prices[0];
        for(int i=1;i& prices) {
        int n=prices.size(), f = 0, g = -prices[0];
        for(int i=1;i

7、买卖股票的最佳时机 III

// 状态机
class Solution {
public:
    int maxProfit(vector& prices) {
        int n=prices.size(); int f[3][n+1][2];
        memset(f,-0x3f,sizeof f);
        for(int i=0;i<=n;i++) f[0][i][0] = 0;        
        for(int j=1;j<=n;j++){
            for(int i=1;i<=2;i++){
                f[i][j][0] = max(f[i][j-1][0], f[i][j-1][1]+prices[j-1]);
                f[i][j][1] = max(f[i][j-1][1], f[i-1][j-1][0]-prices[j-1]);
            }
        }
        int ans=0;
        for(int k=0;k<=2;k++) ans = max(ans, f[k][n][0]);
        return ans;
    }
};

// 前后缀分解
class Solution {
public:
    int maxProfit(vector& prices) {
        int n=prices.size(); int f[n], g[n];
        memset(f,0,sizeof f); memset(g,0,sizeof g);
        for(int i=1,minp=prices[0];i=0;i--){
            maxp = max(maxp, prices[i]);
            g[i] = max(g[i+1], maxp-prices[i]);
        }
        int ans=0;
        for(int i=0;i

8、买卖股票的最佳时机 IV 【状态机】

class Solution {
public:
    int maxProfit(int k, vector& prices) {
        int n=prices.size(); int f[k+1][n+1][2];
        memset(f,-0x3f,sizeof f);
        for(int i=0;i<=n;i++) f[0][i][0] = 0;    

        for(int j=1;j<=n;j++){
            for(int i=1;i<=k;i++){
                f[i][j][0] = max(f[i][j-1][0], f[i][j-1][1]+prices[j-1]);
                f[i][j][1] = max(f[i][j-1][1], f[i-1][j-1][0]-prices[j-1]);
            }
        }
        int ans=0;
        for(int t=0;t<=k;t++) ans = max(ans, f[t][n][0]);
        return ans;
    }
};

9、最佳买卖股票时机含冷冻期【状态机】

class Solution {
public:
    int maxProfit(vector& prices) {
        int n=prices.size();
        vector f(n,0), g(n,0);// f为卖出状态, g为买入状态
        f[0] = 0, g[0]=-prices[0];
        for(int i=1;i

10、买卖股票的最佳时机含手续费【状态机】

class Solution {
public:
    int maxProfit(vector& prices, int fee) {
        int n=prices.size();
        vector f(n,0), g(n,0);
        f[0]=0, g[0]=-prices[0];
        for(int i=1;i

11、正则表达式匹配 【×】

class Solution {
public:
    bool isMatch(string s, string p) {
        int n=s.size(), m=p.size();
        s = ' '+s, p = ' '+p;
        vector> f(n+1,vector(m+1,false));
        f[0][0]=true;
        for(int i=0;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(j+1<=m && p[j+1] == '*')continue;
                if(p[j] == '*'){
                    f[i][j] = f[i][j-2] || i && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.');
                }else if(i && p[j] != '*')
                    f[i][j] = f[i-1][j-1] && (s[i]==p[j] || p[j]=='.');
            }
        }
        return f[n][m];
    }
};

12、通配符匹配

class Solution {
public:
    bool isMatch(string s, string p) {
        int n=s.size(), m=p.size();
        s = ' '+s, p = ' '+p;
        vector> f(n+1,vector(m+1,false));
        f[0][0]=true;
        for(int i=0;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(p[j]=='*') f[i][j] = f[i][j-1] || i && f[i-1][j];
                else f[i][j] = i && (s[i]==p[j] || p[j]=='?') && f[i-1][j-1];
            }
        }
        return f[n][m];
    }
};

[Go Back~](# LeetCode题解)

23、跳跃游戏 VI

class Solution {
public:
    int maxResult(vector& nums, int k) {
        int n=nums.size();
        vector f(n,0); f[0]=nums[0];
        deque q; q.push_back(0);
        for(int i=1;ik) q.pop_front();
            f[i] = f[q.front()] + nums[i];
            while(q.size() && f[i] >= f[q.back()]) q.pop_back();
            q.push_back(i);
        }
        return f[n-1];
    }
};

[Go Back~](# LeetCode题解)

section16-5: 区间DP

1、戳气球

class Solution {
public:
    int maxCoins(vector& nums) {
        int n=nums.size();
        nums.insert(nums.begin(),1); nums.push_back(1);
        vector> f(n+2,vector(n+2,0));
        for(int len=1;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                for(int k=i;k<=j;k++){
                    f[i][j] = max(f[i][j], f[i][k-1]+f[k+1][j]+nums[i-1]*nums[k]*nums[j+1]);
                }
            }
        }
        return f[1][n];
    }
};

2、猜数字大小 II

class Solution {
public:
    int getMoneyAmount(int n) {
        vector>f(n+2,vector(n+2,0));
        for(int len=2;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                f[i][j] = 0x3f3f3f3f;
                for(int k=i;k<=j;k++){
                    f[i][j] = min(f[i][j], max(f[i][k-1], f[k+1][j])+k);
                }
            }
        }
        return f[1][n];
    }
};

3、预测赢家

1、我们可以简化算法 1 中的状态表示,我们设\(f(i,j)\)表示闭区间$ [i, j] \(下,**先手玩家与后手玩家的得分差距的最大值**。 2、初始时,\)f(i,i)=nums[i]\(?。 3、转移时,\)f(i,j)=max(?f(i+1,j)+nums[i],?f(i,j?1)+nums[j])\(。这里的含义为,因为此时是先手玩家,被转移的区间就是后手玩家的得分,所以需要 取相反数 然后转移。 4、最后我们只需要判断\) f(i,j)$是否大于等于 0。

class Solution {
public:
    bool PredictTheWinner(vector& nums) {
        int n=nums.size();
        vector> f(n+1, vector(n+1,0));
        for(int len=1;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                if(len==1) f[i][j] = nums[i-1];
                else{
                    f[i][j] = max(-f[i+1][j]+nums[i-1], -f[i][j-1]+nums[j-1]);
                }
            }
        }
        return f[1][n]>=0;
    }
};

4、最长回文子序列

class Solution {
public:
    int longestPalindromeSubseq(string s) {
        int n=s.size();
        vector> f(n+2,vector(n+2,0));
        f[0][0]=1;
        for(int i=1;i<=n;i++) f[i][i]=1;
        for(int len=2;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                if(s[i-1] == s[j-1]) f[i][j] = max(f[i][j], 2+f[i+1][j-1]);
                else f[i][j] = max(f[i+1][j], f[i][j-1]);
            }
        }
        return f[1][n];
    }
};

5、统计不同回文子序列 【×】区间dp+双端队列

class Solution {
public:
    int countPalindromicSubsequences(string s) {
        int n=s.size(); const int mod=1e9+7;
        vector> f(n+2,vector(n+2,1));
        f[0][0] = 1;
        for(int i=1;i<=n;i++) f[i][i]++;
        for(int len=2;len<=n;len++){
            deque q[4];
            for(int i=1;i<=n;i++){
                q[s[i-1]-'a'].push_back(i);
                int j=i-len+1;
                if(j>=1){
                    for(int k=0;k<4;k++){
                        while(q[k].size() && q[k].front() < j) q[k].pop_front();
                        if(q[k].size()){
                            f[j][i] ++ ;
                            int l = q[k].front(), r = q[k].back();
                            if (l < r)
                                f[j][i] = (f[j][i] + f[l + 1][r - 1]) % mod;
                        }
                    }
                }
            }
        }
        return (f[1][n]+mod-1)%mod;
    }
};

6、石子游戏 【思路同题3】

class Solution {
public:
    bool stoneGame(vector& piles) {
        int n=piles.size();
        vector>f(n+2,vector(n+2,0));
        for(int i=1;i<=n;i++) f[i][i]=piles[i-1];
        for(int len=2;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                f[i][j] = max(-f[i+1][j]+piles[i-1], -f[i][j-1]+piles[j-1]);
            }
        }
        return f[1][n]>0;
    }
};

7、石子游戏 VII

转移:\(f(i,j)=max(sum(i+1,j)?f(i+1,j),sum(i,j?1)?f(i,j?1))\)?

class Solution {
public:
    int stoneGameVII(vector& stones) {        
        int n=stones.size();
        vector sum(n + 1, 0);
        for (int i = 1; i <= n; i++)
            sum[i] = sum[i - 1] + stones[i - 1];

        vector> f(n+2,vector(n+2,-0x3f3f3f));
        for (int i = 1; i <= n; i++) f[i][i] = 0;
        for(int len=2;len<=n;len++){
            for(int i=1;i+len-1<=n;i++){
                int j=i+len-1;
                f[i][j] = max(sum[j]-sum[i]-f[i+1][j], sum[j-1]-sum[i-1]-f[i][j-1]);
            }
        }
        return f[1][n];
    }
};

[Go Back~](# LeetCode题解)

section16-6: 记忆化搜索

1、【树形dp】打家劫舍 III

class Solution {
public:
    int rob(TreeNode* root) {   
        auto f = dfs(root);
        return max(f[0],f[1]);
    }
    vector dfs(TreeNode* root){
        if(!root) return {0,0};
        auto x = dfs(root->left), y = dfs(root->right);
        return {max(x[0],x[1]) + max(y[0],y[1]) , (x[0] + y[0] + root->val)};
    }
};

class Solution {
public:
    unordered_map> hash;
    int rob(TreeNode* root) {
        dfs(root);
        return max(hash[root][0],hash[root][1]);
    }
    void dfs(TreeNode*root){
        if(!root) return;
        dfs(root->left), dfs(root->right);
        hash[root][0] = max(hash[root->left][0], hash[root->left][1]) + max(hash[root->right][0], hash[root->right][1]);
        hash[root][1] = root->val + hash[root->left][0] + hash[root->right][0];
    }
};

2、分发糖果

class Solution {
public:
    int candy(vector& ratings) {
        // 贪心
        int n=ratings.size();
        vectorf(n,1);
        for(int i=0;i f;
    int n;
    int candy(vector& ratings) {
        // 记忆搜索
        n=ratings.size();
        f.resize(n,-1);
        int ans=0;
        for(int i=0;i&ratings, int i){
        if(f[i]!=-1) return f[i];
        f[i]=1;
        if(i+1=0 && ratings[i-1]

3、矩阵中的最长递增路径 【对应-滑雪acwing】

class Solution {
public:
    int dx[4]={-1,0,1,0}, dy[4]={0,-1,0,1};
    vector>f;
    int n,m;
    int longestIncreasingPath(vector>& matrix) {
        n=matrix.size(), m=matrix[0].size();
        f=vector>(n,vector(m,-1));
        int ans=0;
        for(int i=0;i>&matrix, int i, int j){
        if(f[i][j] != -1) return f[i][j];
        f[i][j]=1;
        for(int k=0;k<4;k++){
            int x=dx[k]+i, y=dy[k]+j; 
            if(x>=0 && x=0 && y

4、我能赢吗 【×】

class Solution {
public:
    vector f;
    int n;
    bool canIWin(int m, int total) {
        n=m;
        if((n+1)*n < 2*total) return false;
        if(!total) return true;
        f.resize(1<<(n+1),-1);
        return dfs(0,total);
    }
    bool dfs(int u, int t){
        if(f[u]!=-1) return f[u];
        if(t<=0) return f[u]=false;
        for(int i=1;i<=n;i++){
            if(!(u & 1<

5、猫和老鼠

class Solution {
public:
    int n;
    vector>> f;
    vector> g;
    int dfs(int k,int i,int j){
        int &v=f[k][i][j];
        if (v!=-1) return v;
        if (k>2*n) return v=0;
        if (i==0) return v=1;
        if (i==j) return v=2;
        if (k%2==0){
            bool draw=false;
            for (int ne:g[i]){
                int ans=dfs(k+1,ne,j);
                if (ans==1) return v=1;
                if (ans==0) draw=true;
            }
            if (draw) return v=0;
            return v=2;
        }else{
            bool draw=false;
            for (int ne:g[j]){
                if (ne==0) continue;
                int ans=dfs(k+1,i,ne);
                if (ans==2) return v=2;
                if (ans==0) draw=true;
            }
            if (draw) return v=0;
            return v=1;
        }
    }
    int catMouseGame(vector>& graph) {
        g=graph;
        n=g.size();
        f=vector>>(2*n+2,vector>(n,vector(n,-1)));
        return dfs(0,1,2);
    }
};

[Go Back~](# LeetCode题解)

section16-7: 状态机dp+状压dp

1、最佳买卖股票时机含冷冻期

class Solution {
public:
    int maxProfit(vector& prices) {
        int n=prices.size();
        vector> f(n,vector(2,0));
        f[0][0] = 0, f[0][1] = -prices[0];
        for(int i=1;i=2) f[i][1] = max(f[i-1][1], f[i-2][0]-prices[i]);
            else f[i][1] = max(f[i-1][1], -prices[i]);
        }
        return f[n-1][0];
    }
};

// 状态压缩
class Solution {
public:
    int maxProfit(vector& prices) {
        int n=prices.size();
        int a0 = 0, a1 = -prices[0];
        int last_a0=a0, last_a1 = a1, last_a2=0;
        for(int i=1;i=2) a1 = max(last_a1, last_a2-prices[i]);
            else a1 = max(last_a1, -prices[i]);

            last_a2 = last_a0; last_a1 = a1; last_a0 = a0;
        }
        return a0;
    }
};

2、学生出勤记录 II

const int mod=1e9+7;
class Solution {
public:
    int checkRecord(int n) {
        vector>>f(n+1,vector>(2,vector(3,0)));
        f[0][0][0]=1;
        for(int i=0;i

3、买卖股票的最佳时机含手续费

class Solution {
public:
    int maxProfit(vector& prices, int fee) {
        int n=prices.size();
        vector f(n,0), g(n,0);
        f[0]=0, g[0]=-prices[0];
        for(int i=1;i& prices, int fee) {
        int n=prices.size();
        int a0=0, b0=-prices[0];
        for(int i=1;i

4、我能赢吗 【×】

class Solution {
public:
    vector f;
    int n;
    bool canIWin(int m, int total) {
        n=m;
        if((n+1)*n < 2*total) return false;
        if(!total) return true;
        f.resize(1<<(n+1),-1);
        return dfs(0,total);
    }
    bool dfs(int u, int t){ // 是否使用的状态通过整数u表示
        if(f[u]!=-1) return f[u];
        if(t<=0) return f[u]=false;
        for(int i=1;i<=n;i++){
            if(!(u & 1<

[Go Back~](# LeetCode题解)