0
点赞
收藏
分享

微信扫一扫

LeetCode动态规划专题

云竹文斋 2022-08-18 阅读 58


一、买卖股票的最佳时机

LeetCode动态规划专题_数组


虽然这题标记的是简单,个人感觉还是挺难的。。。也许是我太菜了吧,找了题解才会做,看了大佬的题解后,发现这是一种题型,真是醍醐灌顶。觉得应该总结一下,作为自己的刷题笔记。下面进入正文。

老司机一眼可以看出,这种求差问题可以转换成区间和的问题(emmmmm,我肯定看不出来)。为什么呢?因为我们有牛顿莱布尼茨公式:

在上面的公式中,表示的数组称为前缀和,其实也就是题目所给的当天股票价格,最大的区间和可用动态规划求解,公式如下:

其中,表示在不亏钱的前提下,第天卖出股票所赚的钱,若等于0了,则说明第天卖股票亏了,将重新置0。数组表示相邻两天股票价格的差

int maxProfit(vector<int>& prices) {
if(prices.size() < 2) return 0;//股票只有一天,不赚钱
vector<int> diff;
for(int i=0; i<prices.size()-1; i++){
diff.push_back(prices[i+1] - prices[i]);
}
vector<int> dp(diff.size());
dp[0] = max(0, diff[0]);
int profit = dp[0];
for(int i=1; i<dp.size(); i++){
dp[i] = max(0, dp[i-1] + diff[i]);
profit = max(profit, dp[i]);
}
return profit;
}

提交结果:

LeetCode动态规划专题_数组_11

其实数组是可以优化掉的

int maxProfit(vector<int>& prices) {
if(prices.size() < 2) return 0;
vector<int> dp(prices.size()-1);
dp[0] = max(0, prices[1] - prices[0]);
int profit = dp[0];
for(int i=1; i<dp.size(); i++){
dp[i] = max(0, dp[i-1] + prices[i+1] - prices[i]);
profit = max(profit, dp[i]);
}
return profit;
}

提交结果:

LeetCode动态规划专题_数组_13


其实,dp数组也是可以优化掉的

int maxProfit(vector<int>& prices) {
if(prices.size() < 2) return 0;
int cur_profit = max(0, prices[1] - prices[0]);
int profit = cur_profit;
for(int i=1; i<prices.size()-1; i++){
cur_profit = max(0, cur_profit + prices[i+1] - prices[i]);
profit = max(profit, cur_profit);
}
return profit;
}

提交结果:

LeetCode动态规划专题_子序列_14


总结:求区间和问题和数组元素求差问题是可以相互转化的

线上提交地址:​​买卖股票的最佳时机​​​ 参考题解:​​点击跳转​​

二、求最大子序和

LeetCode动态规划专题_数组_15


代码如下:

int maxSubArray(vector<int>& nums) {
int cur = nums[0];
int res = cur;
for(int i=1; i<nums.size(); i++){
cur = cur > 0 ? cur + nums[i] : nums[i];
if(cur > res) res = cur;
}
return res;
}

其中 cur = cur > 0 ? cur + nums[i] : nums[i] 可理解为:

  • 若当前累加和cur大于0,则可以利用累加和,将当前元素与cur相加,得到更大的累加和
  • 否则,舍弃累加和,从当前元素重新累加,以免使得累加和变小

注:本题应采用逆向思维理解,不是遍历到一个新元素时考虑是否将新元素加入到累加和。而是每次都从此新的元素开始累加,但是要考虑是否利用上前面的累加和。

按照此理解,买卖股票的最佳时机 代码可写为

int maxProfit(vector<int>& prices) {
if(prices.size() < 2) return 0;
int cur_profit = max(0, prices[1] - prices[0]);
int profit = cur_profit;
for(int i=1; i<prices.size()-1; i++){
int diff = prices[i+1] - prices[i];
cur_profit = cur_profit > 0 ? cur_profit + diff : diff;
if(cur_profit > profit) profit = cur_profit;
}
return profit;
}

三、最长上升子序列

LeetCode动态规划专题_i++_16


首先初始化一个全1的dp数组(表示每个元素至少能独立成为一个上升子序列),表示包含0~i号元素中,包含在内的上升序列中最长上升序列的长度

递推公式如下:

递推公式说明

,确定时,重新遍历区间,做如下判断:

  • 时,此时可以和中的部分元素一起组成上升子序列,此时做更新:
  • 时,此时不可以和中的部分元素一起组成上升子序列,不用更新,直接下一次循环

举例:

LeetCode动态规划专题_i++_30


注意:dp数组可不是递增的,仔细理解上面提到的的含义

int lengthOfLIS(vector<int>& nums) {
int N = nums.size();
if(N <= 1) return N;
vector<int> dp(N, 1);
int res = 1;
for(int i=1; i<N; i++){
for(int j=0; j<i; j++){
if(nums[i] > nums[j]){
dp[i] = max(dp[i], dp[j]+1);
}
}
res = max(res, dp[i]);
}
return res;
}


举报

相关推荐

0 条评论