笔记1 第13课 动规2 ——买卖股票最佳时机,打家劫舍,零钱找兑——极客时间算法

之前收藏了极客时间的算法训练营3期 共21课,计划每一课写博客来记录学习,主要形式为

方法类型1

题1

题解

题2

题解

方法类型2

题1

题解

……

题目大体来自leetcode 和 acwing

主要记录和理解代码,所以基本完全搬运了视频题解代码,

个人学习感受体现在大致思路的总结和注释上。


第一题

​​​​​​122. 买卖股票的最佳时机 II

每一天都有持股和不持股的两种状态。

初始化时每一种状态初始值都是极小。

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

第二题

188. 买卖股票的最佳时机 IV

多一些状态而已

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        prices.insert(prices.begin(), 0);
        vector<vector<vector<int>>> f(n + 1,vector<vector<int>>(2, vector<int>(k + 1, -1e9)));
        f[0][0][0] = 0;
        for (int i = 1; i <= n; i++)
            for (int j = 0; j < 2; j++) 
                for (int m = 0; m <= k; m++) {
                    //没有用完次数可以尝试买入
                    if (m > 0) f[i][1][m] = max(f[i][1][m], f[i - 1][0][m - 1] - prices[i]);
                    //卖
                    f[i][0][m] = max(f[i - 1][1][m] + prices[i], f[i][0][m]);
                    //歇
                    f[i][j][m] = max(f[i][j][m], f[i - 1][j][m]);
                }
        int ans = -1e9;
        for (int i = 0; i <= k; i++) {
            //买几次都有可能
            ans = max(ans, f[n][0][i]);
        }
        return ans;
    }
};

第三题

​​​​​​714. 买卖股票的最佳时机含手续费

只需要每次购买时减去费用即可。

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        int n = prices.size();
        prices.insert(prices.begin(), 0);
        vector<vector<int>> f(n + 1, vector<int>(2, -1e9));
        f[0][0] = 0;
        for (int i = 1; i <= n; i++) {
            f[i][1] = max(f[i][1], f[i - 1][0] - prices[i] - fee);
            f[i][0] = max(f[i][0], f[i - 1][1] + prices[i]);
            for (int j = 0; j < 2; j++) 
                f[i][j] = max(f[i][j], f[i - 1][j]);
        }
        return f[n][0];
    }
};

第四题

​​​​​​309. 最佳买卖股票时机含冷冻期

今天的状态规划明天的状态,向后规划。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        vector<vector<vector<int>>> 
            f(n + 1, vector<vector<int>>(2, vector<int>(2, -1e9)));
        prices.insert(prices.begin(), 0);
        f[0][0][0] = 0;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < 2; j++) {
                for (int k = 0; k < 2; k++){
                    if (j == 0 && k == 0)
                        f[i + 1][1][k] = max(f[i + 1][1][k], f[i][j][k] - prices[i + 1]);
                    if (j == 1)
                        f[i + 1][0][1] = max(f[i + 1][0][1], f[i][j][k] + prices[i + 1]);
                    f[i + 1][j][max(0, k - 1)] = max(f[i + 1][j][max(0, k - 1)], f[i][j][k]);
                }
            }
        }
        return max(f[n][0][0], f[n][0][1]);
    }
};

第五题

198. 打家劫舍

之前偷没偷过

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

第六题

213. 打家劫舍 II

头尾相接,进行两次递归,第一次尝试偷第一家,第二次尝试最后一家

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        if (n == 1) return nums[0];//即是头又是尾,特判。
        nums.insert(nums.begin(), 0);
        vector<vector<int>> f(2, vector<int>(2, -1e9));
        //第一次, 可以选择偷第一家
        f[0][0] = 0;
        for (int i = 0; i < n; i++){
            f[i + 1 & 1][0] = max(f[i & 1][0], f[i & 1][1]);
            f[i + 1 & 1][1] = f[i & 1][0] + nums[i + 1];
            for (int j = 0; j < 2; j++){

                f[i & 1][j] = -1e9;
            }
        }
        int ans = f[n & 1][0];
        f[0][0] = -1e9;
        f[0][1] = 0;
        for (int i = 0; i < n; i++){
            f[i + 1 & 1][0] = max(f[i & 1][0], f[i & 1][1]);
            f[i + 1 & 1][1] = f[i & 1][0] + nums[i + 1];
            for (int j = 0; j < 2; j++){

                f[i & 1][j] = -1e9;
            }
        }
        ans = max(ans, max(f[n & 1][0], f[n & 1][1]));
        return ans;
    }
};

第七题

72. 编辑距离

注意初始化的值,为直接构建相应单词所需要的字母数量。

class Solution {
public:
    int minDistance(string word1, string word2) {
        int m = word1.length();
        int n = word2.length();
        word1 = " " + word1;
        word2 = " " + word2;
        vector<vector<int>> f(m + 1, vector<int>(n + 1, 1e9));
        for (int i = 0; i <= m; i++) f[i][0] = i;
        for (int i = 0; i <= n; i++) f[0][i] = i;
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++) {
                f[i][j] = min(f[i - 1][j - 1] + (word1[i] != word2[j]), min(f[i - 1][j] + 1, f[i][j - 1] + 1));
            }
        return f[m][n];
    }
};

第八题

​​​​​​416. 分割等和子集

即找等于总和一半的子集,

|=可以对int使用,但是bool不行

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for (int num : nums) sum += num;
        if (sum % 2 == 1) return false;
        vector<int> f(sum / 2 + 1, false);
        f[0] = true;
        for (int i = 0; i < nums.size(); i++) 
            for (int j = sum / 2; j >= nums[i]; j--) {
                f[j] |= f[j - nums[i]];
            }
        return f[sum / 2];
    }
};

第九题

​​​​​​518. 零钱兑换 II

完全背包问题,相应位置加上之前位置的方案总和。

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        int n = coins.size();
        coins.insert(coins.begin(), 0);
        vector<int> f(amount + 1 , 0);
        f[0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = coins[i]; j <= amount; j++){
                f[j] += f[j - coins[i]];
            }
        }
        return f[amount];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值