1005.K次取反后最大化的数组和
解题思路
贪心在两个点:
1.优先把负数全都取反
2.都是正数时,把最小正数取反
这里比较关键的点就是按照绝对值大小排序,这样最大的负数都会在前面
class Solution {
public:
static bool cmp(int a,int b)
{
return abs(a)>abs(b); //绝对值大的放在前面
}
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)
{
nums[i] *= -1 ; //取反第二步
k--;
}
}
if(k%2==1) nums[nums.size()-1] *= -1; //因为按照绝对值排序,所以最后一个数肯定是最小的
int sum = 0;
for(int i : nums) sum+= i; //求和,这里i是nums中的元素
return sum;
}
};
- 时间复杂度: O(nlogn)
- 空间复杂度: O(1)
134. 加油站
解题思路
贪心贪在我们经过加油站到底是加油还是剩油
我们用一个curSum来取累加剩余油,只要加的为负数之后,就说明i下标之前的所有站点都不适合做起始站点,选取i+1作为起始站点
局部最优:当前累加rest[i]的和curSum一旦小于0,起始位置至少要是i+1,因为从i之前开始一定不行。全局最优:找到可以跑一圈的起始位置
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0; //目前的油量
int totalSum = 0;
int start =0 ; //起始下标
for(int i=0; i<gas.size();i++)
{
curSum +=(gas[i]-cost[i]);
totalSum += (gas[i]-cost[i]);
if(curSum<0)
{
start = i+1; //选择新的起始位置
curSum =0 ;
}
}
if(totalSum<0) return -1; //如果总消耗小于0,肯定是找不到的,如果总消耗是》=0的,肯定可以跑完一圈
return start;
}
};
135. 分发糖果
解题思路
这题比较我们要两边分别考虑,一起比较肯定要顾此失彼
1.右孩比左孩高
局部最优:只要右边评分比左边大,右边的孩子就多一个糖果
全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果
2.左孩比右孩高(从后向前遍历)
局部最优:取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的
全局最优:相邻的孩子中,评分高的孩子获得更多的糖果
这里取较大值,因为可能我比左边孩子大的数,比右边大的还要大,就取较大的
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> candyNums(ratings.size(),1);
int result =0;
for(int i =1 ;i<ratings.size();i++)
{
if(ratings[i]-ratings[i-1]>0)
candyNums[i] = candyNums[i-1] +1 ; //右孩子比左孩子多一个
}
for(int i = ratings.size()-2 ; i>=0 ; i--)
{
if(ratings[i]>ratings[i+1]) //左孩子比右孩子大
candyNums[i] = max(candyNums[i], candyNums[i+1]+1); //在情况1和情况2中取最大值,要同时满足大于邻居的糖果数
}
for(int i: candyNums) result+= i;
return result;
}
};
收获
贪心算法就是做一天忘一天呜呜