目录
? ? ? ? ?本题要使最后的数组和最大,第一次贪心的思路是让绝对值较大的负数优先取反,第二次贪心的思路是在所有负数都变为正数之后,对最小值进行反复取反。一开始就按照绝对值从大到小的顺序对数组进行排序,然后按照两次贪心的思路进行实现。
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 == 1) nums[nums.size() - 1] *= -1;
int result = 0;
for (int num : nums) result += num;
return result;
}
};
? ? ? ? 在第二次贪心实现中可以进行优化的地方在于,不需要对最小元素一次次进行取反,只需要判断还需要取反的次数的奇偶即可,若为偶数则还是当前值,若为奇数则取反,这样操作可以提升运行性能。
? ? ? ? ?利用每个站点增加的油量和到达下一个站点所要消耗的油量可以得到每个站点到达下一站点所能剩下的油量,对每个站点所能剩下的油量依次累加,若一直大于0,那么是一定可以跑完一圈的,当剩余油量累加和小于0时,则表明到达不了下一站点。
? ? ? ? 每个站点的剩余油量rest[i]为gas[i] - cos[i]。i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。
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;
return start;
}
};
? ? ? ? 本题的一个难点在于对于数组中的一个位置如何处理好左右两边的比较。
????????这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼。
????????先确定右边评分大于左边的情况(也就是从左向右遍历),然后再确定左边评分大于右边的情况(从右向左遍历),采用从右向左遍历的方式是因为 rating[5]与rating[4]的比较 要利用上 rating[5]与rating[6]的比较结果,因此得逆向遍历。
class Solution {
public:
int candy(vector<int>& ratings) {
vector<int> candyVec(ratings.size(), 1);
// 从左向右遍历
for (int i = 1; i < ratings.size(); i++){
if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
}
// 从右向左遍历
for (int i = ratings.size() - 2; i >= 0; i--) {
if (ratings[i] > ratings[i + 1]) candyVec[i] = max(candyVec[i + 1] + 1, candyVec[i]);
}
int result = 0;
for (int i = 0; i < candyVec.size(); i++){
result += candyVec[i];
}
return result;
}
};
? ? ? ? 题目代码量不大,但是有点灵活,第一次接触很难想到。