文档链接:https://programmercarl.com/
LeetCode1005.K次取反后最大化的数组和
题目链接:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/
思路:这题还算简单,每次都取最小的元素取反即可。
贪心的思路,局部最优:让绝对值大的负数变为正数,当前数值达到最大,整体最优:整个数组和达到最大。
局部最优可以推出全局最优。
那么如果将负数都转变为正数了,K依然大于0,此时的问题是一个有序正整数序列,如何转变K次正负,让 数组和 达到最大。
那么又是一个贪心:局部最优:只找数值最小的正整数进行反转,当前数值和可以达到最大(例如正整数数组{5, 3, 1},反转1 得到-1 比 反转5得到的-5 大多了),全局最优:整个 数组和 达到最大。
贪心:
class Solution {
public:
int largestSumAfterKNegations(vector<int>& nums, int k) {
while(k--) {
sort(nums.begin(), nums.end());
nums[0] = 0 - nums[0];
}
int sum = 0;
for(int i = 0; i < nums.size(); i++) {
sum += nums[i];
}
return sum;
}
};
卡哥的代码:
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) {
nums[i] *= -1;
k--;
}
}
if(k % 2 != 0) {
nums[nums.size() - 1] *= -1;
}
int sum = 0;
for(int i = 0; i < nums.size(); i++) {
sum += nums[i];
}
return sum;
}
};
LeetCode134.加油站
题目链接:https://leetcode.cn/problems/gas-station/
思路:想法非常巧妙,类似之前做过的最大字数和。用净剩油量来记录,如果总的净剩油量<0,说明无论怎么走全程都不够,直接return -1,如果当前的净剩油量<0,那么就从下一个位置开始走。
贪心:
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int totalSum = 0;
int curSum = 0;
int start = 0;
for(int i = 0; i < gas.size(); i++) {
totalSum += (gas[i] - cost[i]);
}
if(totalSum < 0) return -1;
for(int i = 0; i < gas.size(); i++) {
curSum += (gas[i] - cost[i]);
if(curSum < 0) {
start = i + 1;
curSum = 0;
}
}
return start;
}
};
暴力算法:(虽然超时了,但是我觉得还是需要掌握的)
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
for(int i = 0; i < cost.size(); i++) {
int rest = gas[i] - cost[i];
int index = (i + 1) % cost.size();
while(rest > 0 && index != i) {模拟以i为起点行驶一圈(如果有rest==0,那么答案就不唯一了)
rest += gas[index] - cost[index];
index = (index + 1) % cost.size();
}
if(rest >= 0 && index == i) return i;
}
return -1;
}
};
LeetCode135.分发糖果
题目链接:https://leetcode.cn/problems/candy/
思路:怎么想到遍历两次,一次只求右孩子大于左孩子,另一次求左孩子大于右孩子的。而且两次的遍历方向还不一样。
贪心:
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> candy(ratings.size(), 1);
for(int i = 1; i < ratings.size(); i++) {
if(ratings[i] > ratings[i - 1]) {
candy[i] = candy[i - 1] + 1;
}
}
for(int i = ratings.size() - 2; i >= 0; i--) {
if(ratings[i] > ratings[i + 1]) {
candy[i] = max(candy[i], candy[i + 1] + 1);
}
}
int sum = 0;
for(int i = 0; i < candy.size(); i++) {
sum += candy[i];
}
return sum;
}
};
总结:补完了,但是感觉贪心也太难了吧。毫无套路可言,刷过了也没啥头绪。