贪心无套路,也没有框架之类的,需要多看多练培养感觉才能想到贪心的思路。
题目:455.分发饼干
class Solution {
public:
int findContentChildren(vector<int>& g, vector<int>& s) {
int i=0;
int j=0;
int start=0;
//对饼干的尺寸以及小孩的胃口进行排序
sort(g.begin(),g.end());
sort(s.begin(),s.end());
//饼干尺寸从小到大遍历,去满足小孩的胃口
for(i=0;i<g.size();i++)
{
for(j=start;j<s.size();j++)
{
if(s[j]>=g[i])
{
start=j+1;
break;
}
}
if(j==s.size())
break;
}
return i;
}
};
题目:376.摆动序列
//本题一共分三种情况:
//情况1:原数组中元素个数<3,且存在[1,1]类似情况,此时正确返回结果应为1,但是采用一般方法会返回2;
//情况2:原数组中存在[1,1,1]情况,三数相等,此时正确返回结果应为1,但是采用一般方法会返回2;
//情况3:一般情况,将array[array.size()-1]、nums[i]、nums[i+1]三数进行比较,只要不连续递增/递减,则将nums[i]压入array。
//注意不要在原数组nums上使用nums[i-1]、nums[i]、nums[i+1]三数进行比较,因为如果在遍历的时候三数一起遍历会导致例如[1,3,3,2]数组,会认为[1,3,3]/[3,3,2]均不满足,而获取不到[1,3,2],最后返回错误结果为2,而不是3。
class Solution {
public:
vector<int> array;
int wiggleMaxLength(vector<int>& nums) {
//情况一
if(nums.size()<3)
{
if(nums.size()==2&&nums[0]==nums[1])
return 1;
else
return nums.size();
}
//情况二
if((nums.size()==3)&&(nums[0]==nums[1])&&(nums[1]==nums[2]))
return 1;
//情况三
array.push_back(nums[0]);
for(int i=1;i<nums.size()-1;i++)
{
if((nums[i]-array[array.size()-1])*(nums[i]-nums[i+1])>0)
{
array.push_back(nums[i]);
}
}
//除nums[0]外,数组其余元素只计算凸起值和下凹值,没有计算数组最后元素,此处应加上
return array.size()+1;
}
};
题目:53.最大子数组和
//如果连续数组元素[h,i]之和为负数,则下次计算时应直接跳过该连续数组,直接从sum+=nums[i+1]开始
//不必考虑说[h,h+k]之和为负数,[h+k+1,i]为整数,需要弹出[h,h+k]保留[h+k+1,i]的情况
//因为在一开始[h,h+k]之和为负数时,该串数组就已经会被舍弃。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result=nums[0];
int sum=0;
for(int i=0;i<nums.size();i++)
{
//累计连续数组元素之和
sum+=nums[i];
//更新最大值【注意:这三步操作顺序不能乱】
if(sum>result)
result=sum;
//当连续数组元素之和<0时,归零
if(sum<0)
sum=0;
}
return result;
}
};
题目:122.买卖股票的最佳时机||
//只要今天价格闭昨天价格高,则将股票在今天卖出去,并"假装"买下今天的股票;
//今天股票价格低于昨天,则更新"假装"购买股票的价格
//此处的"假装",即没有真正扣钱,只有当卖股票操作生效时才有用。
class Solution {
public:
int maxProfit(vector<int>& prices) {
int temp=prices[0];
int sum=0;
for(int i=0;i<prices.size();i++)
{
//假装购买今天的股票
if(temp>prices[i])
temp=prices[i];
//卖出股票,并假装购买今天的股票
else
{
sum+=(prices[i]-temp);
temp=prices[i];
}
}
return sum;
}
};
题目:55.跳跃游戏
//贪心原则:判断当前节点可以跳跃的范围内,可以到最远的点,用其更新当前节点
//在更新后,判断该点是否可以跳到最后一个节点,如果可以,则返回true;
//在更新后,如果当前节点无法跳跃到最后一个节点,且当前节点可跳跃值为0,则返回false;
class Solution {
public:
bool canJump(vector<int>& nums) {
int tempMax=nums[0];
for(int i=0;i<nums.size();i++)
{
int Max=0;
int J;
//从当前节点i开始遍历
for(int j=i;j<=i+tempMax;j++)
{
//判断当前节点tempMax与下一节点nums[j]谁能走的更远
//【注意此处判别条件用<=号,否则[2,1,0]无法将当前节点更新到0,导致死循环】
if(Max<=(nums[j]+(j-i)))
{
Max=nums[j]+(j-i);//更新更远值
tempMax=nums[j];//更新当前节点
J=j;//记住当前节点在原数组中的位置
//判断当前节点是否可以到达最后一节点
if(nums[j]+j>=nums.size()-1)
return true;
}
}
//更新当前节点下标
i=J-1;
if(tempMax==0)
return false;
}
return true;
}
};
题目:45.跳跃游戏||
class Solution {
public:
int jump(vector<int>& nums) {
//当数组元素个数为1时,不用跳跃即可到达最后一个节点
int step=0;
if(nums.size()==1)
return 0;
//在当前节点可以跳跃的区间内寻找可以跳跃最远的那个节点
for(int i=1;i<nums.size();i++)
{
int start=0;//用于比较两个节点谁跳得远,弥补索引差
int tempi=0;//保存当前区间内跳的最远的那个节点的索引
int range=nums[i-1];//保存当前节点的跳跃区间
step++;//记录跳跃次数
//如果上一节点的索引+跳跃区间>=数组大小,说明可以跳跃到最后一个节点,则退出
if(range+i-1>=nums.size()-1)
return step;
//遍历寻找上一节点跳跃区间内能够跳跃最远的节点
for(int j=i;j<i+nums[i-1]&&j<nums.size();j++)
{
start++;
if(nums[j]+start>=range)
{
//更新当前节点跳跃区间,保存索引
range=nums[j]+start;
tempi=j;
}
}
//更新当前节点的索引
i=tempi;
}
return step;
}
};
题目:1005.K次取反后最大化的数组和
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
int sum=0;
//每次取反都将数组进行排序,对最小的数nums[0]进行取反
for(int i=0;i<k;i++)
{
sort(nums.begin(),nums.end());
nums[0]=-nums[0];
}
//计算数组元素总和
for(int j=0;j<nums.size();j++)
sum+=nums[j];
return sum;
}
};
题目:134.加油站
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int sum=0;//记录当前油箱油量
int sum1=0;//记录gas油量之和-cost油量之和,当sum1>0说明一定存在某一始发站满足题目要求
int start=0;
for(int i=0;i<gas.size();i++)
{
sum1+=(gas[i]-cost[i]);
//记录始发站start到当前站i路程内,油箱内的当前油量
sum+=(gas[i]-cost[i]);
//如果油箱内的油量<0,此时可以确定以下两点:
//1.原始发站start肯定不能是合法始发站;
//2.[start,i]中不存在合法始发站,因为如果存在[j+1,i]内油箱油量累计>0
//且[start,j]没被舍弃说明[start,j]内油箱油量累计>0。则[start,i]内油箱油量累计>0,不合理!!!!!
if(sum<0)
{
//因此归零当前油箱油量,重置始发站为i+1
sum=0;
start=i+1;
}
}
//当sum1<0说明,环形路径内,加油总量小于耗油量,一定无法环形一周
if(sum1<0)
return -1;
return start;
}
};
题目:135.分发糖果
//注意:本题的难点在于,无法一次同时比较当前孩子的左右两边孩子的分数进行分配糖果
//所以只能先只比较当前孩子与其左孩子相比,分数越高糖果数要大
//从左到右分配完毕以后,开始从右到左比较
//比较当前孩子与其右孩子相比,分数越高糖果数要大
class Solution {
public:
int candy(vector<int>& ratings) {
if(ratings.size()==1)
return 1;
//先将所有孩子的糖果数都初始化为1
vector<int> sugur(ratings.size(),1);
//从左向右比较,当右边孩子的分数闭左边高,右边孩子的糖果数=左边孩子糖果数+1
for(int i=1;i<ratings.size();i++)
{
if(ratings[i]>ratings[i-1])
{
sugur[i]=sugur[i-1]+1;
}
}
//从左向右比较,如果左孩子的分数比右边高,如果左孩子的糖果数本来就比右孩子高,则不变,
//否则左孩子的糖果数=右边孩子糖果数+1
for(int i=ratings.size()-2;i>=0;i--)
{
if(ratings[i]>ratings[i+1])
{
sugur[i]=max(sugur[i],sugur[i+1]+1);
}
}
//记录分发给孩子的糖果总数
int SUM=0;
for(int i=0;i<ratings.size();i++)
{
SUM+=sugur[i];
}
return SUM;
}
};
题目:406.根据身高重建队列
// 排序完的people: [[7,0], [7,1], [6,1], [5,0], [5,2],[4,4]]
// 插入的过程:排序完后的数组,每次插入result数组的位置为people[i][1];
// 插入[7,0]:[[7,0]]
// 插入[7,1]:[[7,0],[7,1]]
// 插入[6,1]:[[7,0],[6,1],[7,1]]
// 插入[5,0]:[[5,0],[7,0],[6,1],[7,1]]
// 插入[5,2]:[[5,0],[7,0],[5,2],[6,1],[7,1]]
// 插入[4,4]:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
// 数组的插入操作太耗时间,可以考虑换成链表操作
class Solution {
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
//1.将数组进行排序 [[7,1], [7,0], [6,1], [5,2],[5,0], [4,4]]
sort(people.begin(),people.end());
reverse(people.begin(),people.end());
//记录每种身高的人数
unordered_map<int,int> mat;
for(int i=0;i<people.size();i++)
{
mat[people[i][0]]++;
}
//2.将数组进行排序排序成[[7,0], [7,1], [6,1], [5,0], [5,2],[4,4]]
for(int j=0;j<people.size();j++)
{
int len=mat[people[j][0]];
reverse(people.begin()+j,people.begin()+j+len);
j=j+len-1;
}
//3.将数组中的元素挨个插入结果数组中
vector<vector<int>> result;
for(int i=0;i<people.size();i++)
{//注意:数组元素的插入方法
result.insert(result.begin()+people[i][1],people[i]);
}
return result;
}
};
题目:452.用最少数量的箭引爆气球
class Solution {
public:
int findMinArrowShots(vector<vector<int>>& points) {
int num=1;
//首先需要将气球引爆区间进行排序
sort(points.begin(),points.end());
//创建一个二维数组用来临时保存当前弓箭可以射穿的区间
vector<int> array=points[0];
for(int i=1;i<points.size();i++)
{
//如果当前遍历的区间与上一弓箭可以射穿的区间存在区间重合,取其交集,并继续遍历下一气球引爆区间
if(array[1]>=points[i][0])
{
array[0]=points[i][0];
array[1]=min(array[1],points[i][1]);
continue;
}
//如果当前遍历的区间与上一弓箭可以射穿的区间不存在交集,则累加弓箭数,更新当前弓箭可以射穿的区间
else
{
num++;
array=points[i];
}
}
return num;
}
};
题目:763.划分字母区间
class Solution {
public:
//用于判断两个区间之间是否有重合
bool isInpart(vector<int> array1,vector<int> array2)
{
if(array2[0]>=array1[0]&&array2[0]<array1[1])
return true;
return false;
}
vector<int> partitionLabels(string s) {
unordered_map<char,int> mat;
vector<vector<int>> array;
//采用哈希表获取字符串中每个字符的左区间
for(int i=0;i<s.length();i++)
{
if(mat[s[i]]==0)
mat[s[i]]=i+1;
else
continue;
}
//采用哈希表获取字符串中每个字符的右区间
for(int j=s.length()-1;j>=0;j--)
{
if(mat[s[j]]!=0)
{
array.push_back({mat[s[j]],j+1});
mat[s[j]]=0;
}
else
continue;
}
//将获取的区间集合数组进行排序!!!
sort(array.begin(),array.end());
vector<vector<int>> temp;
temp.push_back(array[0]);
//将所有存在交集的区间进行合并
for(int i=1;i<array.size();i++)
{
if(isInpart(temp[temp.size()-1],array[i]))
{
temp[temp.size()-1][1]=max(array[i][1],temp[temp.size()-1][1]);
}
else
{
temp.push_back(array[i]);
}
}
vector<int> result;
//计算所有合并后的区间长度,并+1
for(int i=0;i<temp.size();i++)
{
result.push_back(temp[i][1]-temp[i][0]+1);
}
return result;
}
};
题目:56.合并区间
class Solution {
public:
//用于判断两个区间之间是否有重合
bool isInpart(vector<int> array1,vector<int> array2)
{
if(array2[0]>=array1[0]&&array2[0]<=array1[1])
return true;
return false;
}
vector<vector<int>> merge(vector<vector<int>>& intervals) {
vector<vector<int>> temp;
//对数组中的区间进行排序
sort(intervals.begin(),intervals.end());
temp.push_back(intervals[0]);
//将所有存在交集的区间进行合并
for(int i=1;i<intervals.size();i++)
{
if(isInpart(temp[temp.size()-1],intervals[i]))
{
temp[temp.size()-1][1]=max(intervals[i][1],temp[temp.size()-1][1]);
}
else
{
temp.push_back(intervals[i]);
}
}
return temp;
}
};
题目:738.单调递增的数字
class Solution {
public:
long monotoneIncreasingDigits(int n) {
//情况一:个位数直接返回
if(n<10)
return n;
//情况二:普通情况
//先将n拆解成各个数存入数组,用于后续判断
vector<int> array;
while(n>0)
{
int temp=n%10;
array.push_back(temp);
n=n/10;
}
//eg:(1)13234256--->直接将4减1,将2及之后的数都改为9----->13233999
// (2)13233999----->将3减1,直接将2及以后的数都改为9------->12999999
for(int i=0;i<array.size()-1;i++)
{
if(array[i]<array[i+1])
{
array[i+1]=array[i+1]-1;
int n=i;
while(n>=0)
{
array[n]=9;
n--;
}
}
}
//最后再将数组中的数组合成一个整数返回
long result=0;
for(int i=array.size()-1;i>=0;i--)
{
result+=array[i];
result=result*10;
}
return result/10;
}
};
题目:714.买卖股票的最佳时机含手续费
//用动态规划做!!!!!!
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int buy=prices[0];
int money=0;
for(int i=1;i<prices.size();i++)
{
if(prices[i]-buy-fee>0)
{
money+=prices[i]-buy-fee;
buy=prices[i]-fee;//很关键,需要减去fee,不理解
}
if(prices[i]<buy)
buy=prices[i];
}
return money;
}
};
可以从程序中看出,在卖出股票当天,如果购买股票,购买的价格并不是当天股票的价格,而是股票的价格-手续费。原因如下:
卖出股票当天其实并没有真正将股票卖出,只是暂时收获利润。此时可以看成当天买股票时的价格=当初买股票的价格+利润+手续费。(利润+手续费)这部分钱一部分收入囊中,一部分交手续。即可以看成之前从没有做过股票交易,但是交了手续肥。所以当天买股票的价格=当天股票的价格-手续费。其实我也不大清楚,这种题最好用动态规划做.........
参考
代码随想录