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 就可以了。