最大子序和 买股票的最佳时机|| 跳跃游戏

发布于:2025-03-29 ⋅ 阅读:(27) ⋅ 点赞:(0)

1.给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

  • 输入: [-2,1,-3,4,-1,2,1,-5,4]
  • 输出: 6
  • 解释:  连续子数组  [4,-1,2,1] 的和最大,为  6。

#include <bits/stdc++.h>
using namespace std;
int find(vector<int>& num)
{
    int result=INT_MIN;
    int count=0;
    for(int i=0;i<num.size();i++)
    {
        count+=num[i];
        if(count>result)
        result=count;
        if(count<0)
        count=0;
    }
    return result;
    
}
int main()
{
    vector<int> num={-2,1,-3,4,-1,2,1,-5,4};
    int t=find(num);
    cout<<t;
    return 0;
}

思路:对于这道题,给了我们一个数组让我们求连续子序列和最大值,我们先来找贪心的地方,如果 -2 1 在一起,计算起点的时候,一定是从 1 开始计算,因为负数只会拉低总和,这就是贪心贪的地方!

局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。

全局最优:选取最大“连续和”。

遍历 nums,从头开始用 count 累积,如果 count 一旦加上 nums[i]变为负数,那么就应该从 nums[i+1]开始从 0 累积 count 了,因为已经变为负数的 count,只会拖累总和。这相当于是暴力解法中的不断调整最大子序和区间的起始位置

区间的终止位置,其实就是如果 count 取到最大值了,及时记录下来了。这样相当于是用 result 记录最大子序和区间和(变相的算是调整了终止位置)

2.给定一个数组,它的第  i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

#include <bits/stdc++.h>
using namespace std;
int find(vector<int>& num)
{
    int result=0;
    for(int i=1;i<num.size();i++)
    {
        result+=max(num[i]-num[i-1],0);
    }
    return result;
 } 
 int main()
 {
     vector<int> num={7,1,5,10,3,6,4};
     int t=find(num);
     cout<<t;
     return 0;
 }

思路:想获得利润至少要两天为一个交易单元,这道题目可能我们只会想,选一个低的买入,再选个高的卖,再选一个低的买入.....循环反复。

如果想到其实最终利润是可以分解的,那么本题就很容易了!

假如第 0 天买入,第 3 天卖出,那么利润为:prices[3] - prices[0]。

相当于(prices[3] - prices[2]) + (prices[2] - prices[1]) + (prices[1] - prices[0])。

此时就是把利润分解为每天为单位的维度,而不是从 0 天到第 3 天整体去考虑!

那么根据 prices 可以得到每天的利润序列:(prices[i] - prices[i - 1]).....(prices[1] - prices[0])。

第一天没有利润,至少要第二天才会有利润,所以利润的序列比股票序列少一天。

其实我们需要收集每天的正利润就可以,收集正利润的区间,就是股票买卖的区间,而我们只需要关注最终利润,不需要记录区间

那么只收集正利润就是贪心所贪的地方。

局部最优:收集每天的正利润,全局最优:求得最大利润

3.给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个位置。

#include <bits/stdc++.h>
using namespace std;
bool find(vector<int>& num)
{
    int cover=0;
    if(num.size()==1)
    return true;
    for(int i=0;i<=cover;i++)
    {
        cover=max(i+num[i],cover);
        if(cover>=num.size()-1)
        return true;
    }
    return false;
 } 
 int main()
 {
     vector<int> num={3,2,1,0,4};
     cout<<((find(num)==1)?"True":"False");
     return 0;
 }

思路:对于这道题其实跳几步无所谓,关键在于可跳的覆盖范围,不一定非要明确一次究竟跳几步,每次取最大的跳跃步数,这个就是可以跳跃的覆盖范围。这个范围内,别管是怎么跳的,反正一定可以跳过来,那么这个问题就转化为跳跃覆盖范围究竟可不可以覆盖到终点。

每次移动取最大跳跃步数(得到最大的覆盖范围),每移动一个单位,就更新最大覆盖范围。

贪心算法局部最优解:每次取最大跳跃步数(取最大覆盖范围),整体最优解:最后得到整体最大覆盖范围,看是否能到终点

i 每次移动只能在 cover 的范围内移动,每移动一个元素,cover 得到该元素数值(新的覆盖范围)的补充,让 i 继续移动下去。

而 cover 每次只取 max(该元素数值补充后的范围, cover 本身范围)。

如果 cover 大于等于了终点下标,直接 return true 就可以了。