代码随想录Day34 | 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果
1005.K次取反后最大化的数组和
文档讲解:代码随想录
视频讲解: 贪心算法,这不就是常识?还能叫贪心?LeetCode:1005.K次取反后最大化的数组和
状态
尽可能翻转所有负数,如果k比负数个数多,那么就不断翻转最小的数(包括负数的绝对值)。
//选择最小的数进行翻转
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(),nums.end());
//统计负数
int nenums = 0;
for(int i = 0;i<nums.size();i++)
{
if(nums[i]<0)
{
nenums++;
}
}
//返回的结果
int res = 0;
//当nenums为0
if(nenums == 0)
{
if(k%2==0)
{
for(int i = 0;i<nums.size();i++)
{
res += nums[i];
}
}
else
{
res += -1*nums[0];
for(int i = 1;i<nums.size();i++)
{
res += nums[i];
}
}
}
//当nenums 不为0且小于k
else
{
if(nenums<k)
{
for(int i = 0;i<nums.size();i++)
{
if(i<nenums)
{
res+=-1*nums[i];
}
else
{
res += nums[i];
}
}
int temp = -1*nums[nenums-1];
if(nenums < nums.size()) temp = (-1*nums[nenums-1]) > nums[nenums] ? nums[nenums] : (-1*nums[nenums-1]);
res -= temp;
int a = k-nenums;
while(a--)
{
temp = -1*temp;
}
res+=temp;
}
else
{
for(int i = 0;i<nums.size();i++)
{
if(i<k)
{
res += -1*nums[i];
}
else{
res += nums[i];
}
}
}
}
return res;
}
};
代码随想录中给出了另外一种方法,不用考虑这么多情况,即按绝对值排序,然后遇到负数翻转,并记录k的变化,如果遍历完k还有那么就一直翻转最小的数,直到k用完。
//选择最小的数进行翻转
class Solution {
static bool cmp(int a,int b)
{
return abs(a) > abs (b);
}
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
sort(nums.begin(),nums.end(),cmp);
for(int i =0;i<nums.size();i++)
{
if(nums[i]<0 && k>0)
{
k--;
nums[i] *= -1;
}
}
if(k%2 == 1)
{
nums[nums.size()-1] *= -1;
}
int res = 0;
for(int i=0;i<nums.size();i++)
{
res += nums[i];
}
return res;
}
};
134.加油站
文档讲解:代码随想录
视频讲解: 贪心算法,得这么加油才能跑完全程!LeetCode :134.加油站
状态
局部最优:一个连续区间内的省油量之和大于0,说明一定可以在这个区间循环,如果小于0,那么就需要更新区间的起点重新计算。
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
//记录当前这个区间的剩油量
int curres = 0;
//记录整个数组的剩油量
int totalres = 0;
//需要更新的起始点
int res = 0;
for(int i=0;i<gas.size();i++)
{
curres += gas[i]-cost[i];
totalres += gas[i]-cost[i];
//当这个区间的剩油量小于0,舍去更新res
if(curres < 0)
{
res = i+1;
curres = 0;
}
}
if(totalres < 0)
{
return -1;
}
return res;
}
};
135.分发糖果
文档讲解:代码随想录
视频讲解: 贪心算法,两者兼顾很容易顾此失彼!LeetCode:135.分发糖果
状态
考虑左右对中间的影响,可以先考虑一边,在考虑另一边时,增加判断即可
对于这道题,可以先只考虑当前孩子的评分比左边孩子高的情况,那么就是左边孩子的糖果数+1.
接着考虑当前孩子的评分比右边孩子高的情况,同样是右边孩子的糖果数+1,但由于之前有左边孩子的影响,为了满足左右两边孩子的共同影响,应当选择两个结果的最大值
//i+1 比 i 大那么就增加一个糖果
//i-1比i 大 那么也增加一个糖果
class Solution {
public:
int candy(vector<int>& ratings) {
//首先初始化糖果数组全为1
vector<int> candy(ratings.size(),1);
//先考虑右边孩子比左边大的情况 比较当前位置和其左边位置
//如果大,那么就加1
for(int i=1;i<ratings.size();i++)
{
if(ratings[i-1]< ratings[i])
{
candy[i] = candy[i-1]+1;
}
}
//再考虑左边孩子比右边大的情况 比较当前位置和其右边位置
//从后向前
//由于此时已经存在右边比左边大的结果,如果大,那么结果应当为右边的结果+1,
//当然当前这个位置还存在一个结果,那么应当取这两个的最大值
for(int i = ratings.size()-2;i>=0;i--)
{
if(ratings[i+1]<ratings[i])
{
int temp = candy[i+1]+1;
candy[i] = max(candy[i],temp);
}
}
int res = 0;
for(int i = 0;i<candy.size();i++)
{
res += candy[i];
}
return res;
}
};