代码随想录算法训练营第34天| 1005. K次取反后最大化的数组和 、134. 加油站、135. 分发糖果
1005. K次取反后最大化的数组和
从小到大开始排序,然后根据k的值从头到尾开始取反,首先将负值进行取反,如果负值都没有了,k值依旧大于0,那么就可以将当下绝对值最小的,反复取反如果遇到0,直接停止取反操作。
class Solution {
public:
// 绝对值从大到小排序
static bool cmp(int a, int b) {
return abs(a) > abs(b);
}
int largestSumAfterKNegations(vector<int>& nums, int k) {
int sum = 0;
sort(nums.begin(), nums.end(), cmp);
for (int i = 0; i < nums.size(); ++i) {
if (k > 0 && nums[i] < 0) {
nums[i] *= -1;
--k;
}
}
if (k % 2 == 1) {
nums[nums.size() - 1] *= -1;
}
for (int a : nums) sum += a;
return sum;
}
};
134. 加油站
// 暴力穷举法
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];
// index就是下一个下标(环形,所以使用取余操作)
int index = (i + 1) % cost.size();
while (rest > 0 && index != i) {
rest -= cost[index];
rest += gas[index];
index = (index + 1) % cost.size();
}
// 以i为起点跑了一圈,剩余油量rest非负,返回了初始的位置
if (rest >= 0 && index == i) return i;
}
// rest 为负 就回不了原点
return -1;
}
};
从全局考虑,细分可能遇到的情况
class Solution {
public:
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int curSum = 0;
int minSum = INT_MAX;
// 计算环路油量剩余是否大于0, 以及找到从0出发时最小剩余油量
for (int i = 0; i < gas.size(); ++i) {
int rest = gas[i] - cost[i];
curSum += rest;
minSum = min(curSum, minSum);
}
// 环路油量不足, 无法绕行
if (curSum < 0) return -1;
// 从0处出发没有遇到油不足的情况, 可行
if (minSum >= 0) return 0;
// minSum 为负。从后往前计算剩余油量之和, 找出第一个之和能将minSum置为非负数的位置, 从该位置出发可行
for (int i = gas.size() - 1; i >= 0; i--) {
int rest = gas[i] - cost[i];
minSum += rest;
if (minSum >= 0) {
return i;
}
}
return -1;
}
};
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];
// 当前累加rest[i]和 curSum一旦小于0
if (curSum < 0) {
// 起始位置更新为i+1, 说明[start, i]求和为负,重新置零 curSum
start = i + 1;
curSum = 0;
}
}
if (totalSum < 0) return -1;
return start;
}
};
135. 分发糖果
使用两次遍历,分别是从前往后,考虑右边的孩子比左边的孩子大的情况,此时,candy[i] = candy[i + 1];从后往前,考虑的就是左边的孩子比右边孩子大的情况,candy[i] = max(candy[i], candy[i + 1] + 1)。
本题的关键就是一次只考虑一种情况,使用了两次贪心
class Solution{
public:
int candy(vector<int>& ratings) {
int res = 0;
// 因为至少一个糖,全部初始化为1
vector<int> candy(rating.size(), 1);
// 从前往后
for (int i = 0; i < ratings.size() - 1; ++i) {
if (ratings[i + 1] > ratings[i]) {
candy[i + 1] = candy[i] + 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);
}
}
for (int i = 0; i < candy.size(); ++i) {
res += candy[i];
}
return res;
}
};