代码随想录算法训练营day51|| 309.最佳买卖股票时机含冷冻期 ||714.买卖股票的最佳时机含手续费 ||300.最长递增子序列

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

思路:

这题相对于买卖股票最佳时机2多了一个冷冻期的条件,买卖股票最佳时机2每天只用考虑两个状态,买入股票状态和卖出股票的状态。这题多了一个条件就需要多出一些状态求解,这题就需要总的每天可能分为四个状态:1.持有股票 2.第i天之前不持有股票(前一天是冷冻期,或者前一天超过冷冻期并且不持有股票) 3.第i天卖出股票 4.当天为冷冻期

为什么不把状态二和状态三结合在一起呢?因为状态四是冷冻期,状态四之前的一天一定是状态三,股票卖出的当天。但是如果将状态二和三结合在一起了,那么就无法保证状态四的前一天是刚好卖出股票的那一天,冷冻期的剩余金额一定是卖出股票当天的剩余金额。

动规五部曲:

1.dp[i][j]及其下标的定义:第i天状态j下的最大剩余金额.

2.递推公式:dp[i][0]=max(dp[i-1][0],max(dp[i-1][1],dp[i-1][3])-prices[i])

dp[i][1]=max(dp[i-1][1],dp[i-1][3]);

dp[i][2]=dp[i-1][1]+prices[i];        dp[i-1][3]=dp[i-1][2];

3.初始化:dp[0][0]=-prices[0],其他初始化为0;

4.遍历顺序:从小到大

5.验证dp

class Solution {
public:
    int maxProfit(vector& prices) {
        int n = prices.size();
        if (n == 0) return 0;
        vector> dp(n, vector(4, 0));
        dp[0][0] -= prices[0]; // 持股票
        for (int i = 1; i < n; i++) {
            dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
            dp[i][2] = dp[i - 1][0] + prices[i];
            dp[i][3] = dp[i - 1][2];
        }
        return max(dp[n - 1][3],max(dp[n - 1][1], dp[n - 1][2]));
    }
};

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

思路:

这题相较于买卖股票的最佳时机就主要差别在于递推公式上,当你在第i天持有时没什么差别,要么在前一天就持有了,要么当天买入。但是在卖出的时候就会有所差距,如果是当天卖出,还要减去手续费。dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]-fee);

class Solution {
public:
    int maxProfit(vector& prices, int fee) {
        int n = prices.size();
        vector> dp(n, vector(2, 0));
        dp[0][0] -= prices[0]; // 持股票
        for (int i = 1; i < n; 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 max(dp[n - 1][0], dp[n - 1][1]);
    }
};

300.最长递增子序列

思路:

最长上升子序列是动规的经典题目,这里dp[i]可以根据dp[j](j

1.dp[i]的定义:

dp[i]表示i之前包括i的以nums[i]结尾最长上升子序列的长度。注意:这个是以nums[i]结尾的最长子序列的长度,而不是遍历到数组i时的最长子序列长度,所以当遍历完nums之后,最长子序列长度不一定是dp[nums.size()-1].可能是前面的元素。

2.状态转移方程。

位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列+1的最大值(前提当然是位置i的值大于j位置的值).所以:if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);

3.初始化

每一个i,对应的dp[i]起始大小最少为1.

4.确定遍历顺序:

从前到后遍历

class Solution {
public:
    int lengthOfLIS(vector& nums) {
        if (nums.size() <= 1) return nums.size();
        vector dp(nums.size(), 1);
        int result = 0;
        for (int i = 1; i < nums.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
            }
            if (dp[i] > result) result = dp[i]; // 取长的子序列
        }
        return result;
    }
};

你可能感兴趣的:(算法,动态规划)