
初篇我们介绍了贪心算法的相关背景知识,本篇我们将结合具体题目,进一步深化大家对于贪心算法的理解和运用。
子序列 是由子数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。我们在考虑最⻓递增⼦序列的⻓度的时候,其实并不关⼼这个序列⻓什么样⼦,我们只是关⼼最后 ⼀个元素是谁。这样新来⼀个元素之后,我们就可以判断是否可以拼接到它的后⾯。
因此,我们可以创建⼀个数组,统计⻓度为 x 的递增⼦序列中,最后⼀个元素是谁。为了尽可能
的让这个序列更⻓,我们仅需统计⻓度为 x 的所有递增序列中最后⼀个元素的「最⼩值」。
统计的过程中发现,数组中的数呈现「递增」趋势,因此可以使⽤「⼆分」来查找插⼊位置。
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n=nums.size();
vector<int> ret;
ret.push_back(nums[0]);
for(int i=1;i<n;i++)
{
if(nums[i]>ret.back())
{
ret.push_back(nums[i]);
}//满足递增条件,直接插入
else
//二分查找插入位置
{
int left=0,right=ret.size()-1;
while(left<right)
{
int mid=(left+right)/2;
if(ret[mid]<nums[i])
{
left=mid+1;
}
else
{
right=mid;
}
}
ret[left]=nums[i];//放在left位置上
}
}
return ret.size();
}
};最⻓递增⼦序列的简化版。
不⽤⼀个数组存数据,仅需两个变量即可。也不⽤⼆分插⼊位置,仅需两次⽐较就可以找到插⼊位
置。
class Solution {
public:
bool increasingTriplet(vector<int>& nums) {
int a=nums[0],b=INT_MAX;
for(int i=1;i<nums.size();i++)
{
if(nums[i]>b) return true;
else if(nums[i]>a) b=nums[i];//更新b的值
else if(nums[i]<a) a=nums[i];//更新a的值
}
return false;//说明不存在
}
};本题可以通过双指针进行贪心优化。
贪⼼策略: 找到以某个位置为起点的最⻓连续递增序列之后(设这个序列的末尾为 j 位置),接下来直接 以 j + 1 的位置为起点寻找下⼀个最⻓连续递增序列。
class Solution {
public:
int findLengthOfLCIS(vector<int>& nums) {
int n=nums.size();
int ret=0;//最终返回长度
for(int i=0;i<n;)
{
int j=i+1;
while(j<n && nums[j]>nums[j-1]) //处于连续递增之中
{
j++;
}
ret=max(ret,j-i);//更新最大长度
i=j;//更新起点
}
return ret;
}
};需要注意:本题中只能交易一次(即只能买入和卖出各一次)
贪心策略:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int ret=0;//处理不能获取利润的情况
int prev=INT_MAX;//前缀最小值
for(int i=0;i<prices.size();i++)
{
ret=max(ret,prices[i]-prev);
prev=min(prev,prices[i]);
}
return ret;
}
};本篇关于贪心算法的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!