LeetCode题解随笔:动态规划(二)

1139. 最大的以 1 为边界的正方形

int largest1BorderedSquare(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();
        // 动态规划法
        vector<vector<int>> up(m + 1, vector<int>(n + 1, 0));   // (x,y)及上方连续1的个数
        vector<vector<int>> left(m + 1, vector<int>(n + 1, 0));   // (x,y)及左方连续1的个数
        // 递推公式
        int res = 0;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (grid[i - 1][j - 1] == 1) {
                    up[i][j] = up[i - 1][j] + 1;
                    left[i][j] = left[i][j - 1] + 1;
                    // 设以(x,y)为正方形右下顶点的正方形边长为l
                    // 左下顶点(x - l + 1, y)
                    // 右上顶点(x, y - l + 1)
                    int l = min(left[i][j], up[i][j]);
                    while (up[i][j - l + 1] < l || left[i - l + 1][j] < l) {
                        l--;
                    }
                    res = max(res, l);
                }
            }
        }
        return res * res;
    }

1653. 使字符串平衡的最少删除次数

    int minimumDeletions(string s) {
        // 遇到b跳过,遇到a考虑删除 / 删除前方所有的b
        int cnt_b = 0, res = 0;
        for (auto c : s) {
            if (c == 'a')    res = min(res + 1, cnt_b);
            else cnt_b++;
        }
        return res;
    }

博弈问题

1140. 石子游戏 II

    int stoneGameII(vector<int>& piles) {
        int n = piles.size(), sum = 0;
        // dp[i][j]: 剩余[i : len - 1],M = j时,先取的人能获得的最多石子数
        vector<vector<int>>dp(n, vector<int>(n + 1, 0));
        // 递推公式
        for (int i = n - 1; i >= 0; --i) {
            sum += piles[i];
            for (int M = 1; M <= n; ++M) {
                // 剩下的堆数能够直接全部取走,那么最优的情况就是剩下的石子总和
                if (i + 2 * M >= n) {
                    dp[i][M] = sum;
                }
                // 剩下的堆数不能全部取走,那么最优情况就是让下一个人取的更少
                else {
                    // 遍历所有可能的取值
                    for (int x = 1; x <= 2 * M; ++x) {
                        dp[i][M] = max(dp[i][M], sum - dp[i + x][max(x, M)]);
                    }
                }
            }
        }
        return dp[0][1];
    }

二维DP

小红取数

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n, k;
    cin >> n >> k;
    vector<long long> nums(n);
    for(int i = 0; i < n; ++i){
        cin >> nums[i];
    }

    // dp[i][j]:取前i个数字,模k为j的最大数
    vector<vector<long long>> dp(n+1, vector<long long>(k, 0));
    for (int i = 0; i < k; i++) {
        dp[0][i] = -1;
    }
    dp[0][0] = 0;
    for(int i = 1; i <= n; ++i){
        for(int j = 0; j < k; ++j){
            long long temp = (j + k - nums[i - 1] % k) % k;
            if (dp[i - 1][temp] != -1)
                dp[i][j] = max(dp[i-1][j], dp[i - 1][temp] + nums[i - 1]);
            else
                dp[i][j] = dp[i-1][j];
        }
    }
    if(dp[n][0]==0) 
        cout << -1 << endl;
    else
        cout << dp[n][0] << endl;;
}

树型DP

红和蓝

#include <iostream>
#include <vector>
using namespace std;

vector<int> color;
int dp[100001]={0}; //dp[i]!=0  表示这个位置需要上一个色 (一般是 [parent,son] 一组)

// dfs1: 研究能否成功上色
void dfs1(vector<vector<int>> &mp, int pre, int cur)
{
    for(int i = 0;i < mp[cur].size(); i++)
    {
        int child = mp[cur][i];
        if(child == pre)
            continue; //跳过环路
        dfs1(mp, cur, child);

        if(!dp[cur] && !dp[child])
        {
            dp[cur] = cur;
            dp[child] = cur;  //全部调整为index数值
        }
    }
}

// dfs2: 调整上色: 遍历过程中记录当前的dp[]与parent是否相同即可
void dfs2(vector<vector<int>> &mp, int pre, int cur){
    for(int i = 0;i < mp[cur].size(); i++){
        int child = mp[cur][i];
        if(child == pre)
            continue; //跳过环路
        if(dp[cur] == dp[child]){
            color[child] = color[cur];
        }
        else{
            color[child] = !color[cur];
        }
        dfs2(mp, cur, child);
    }
}

int main() {
    int n;
    cin >> n;
    color.resize(n + 1);
    vector<vector<int>> mp(n+1, vector<int>());
    for(int i = 1; i <= n-1; ++i){
        int x,y;
        cin >> x >> y;
        mp[x].push_back(y);
        mp[y].push_back(x);
    }

    dfs1(mp, -1, 1);
    for(int i = 1; i <= n; ++i){
        if(dp[i] <= 0){
            cout << -1 << endl;
            return 0;
        }
    }

    dfs2(mp, -1, 1);
    string res;
    for(int i = 1; i <= n; ++i){
        res.push_back(color[i] == 0 ? 'R' : 'B');
    }
    cout << res << endl;
}

二叉树中的最大路径和

#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
using namespace std;

int dfs(vector<vector<int>> &mp, vector<int> &val, vector<int> &dp, int root){
    if(mp[root].empty()){
        dp[root] = val[root];
        return val[root];
    }
    if(mp[root].size() == 1){
        // 最好子节点为负不如不选
        int best_child  = max(dfs(mp, val, dp, mp[root][0]), 0);
        int cur_best = val[root] + best_child;
        dp[root] = cur_best;
        return cur_best;
    }
    else{
        int best_child_l  = max(dfs(mp, val, dp, mp[root][0]), 0);
        int best_child_r  = max(dfs(mp, val, dp, mp[root][1]), 0);
        int cur_best = val[root] +  max(best_child_l, best_child_r);
        dp[root] = val[root] +  best_child_l + best_child_r;
        return cur_best;
    }
}

int main() {
    int n;
    cin >> n;
    vector<int> val(n+1);
    vector<int> dp(n+1, INT_MIN);
    for(int i = 1; i <= n ; ++i){
        cin >> val[i];
    }
    vector<vector<int>> mp(n+1, vector<int>());
    for(int i = 1; i <= n ; ++i){
        int x;
        cin >> x;
        mp[x].push_back(i);
    }

    dfs(mp, val, dp, 1);
    cout << *max_element(dp.begin(), dp.end()) << endl;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值