1005.K 次取反后最大化的数组和
思路好简单,但写起来一直出错,难受啊
思路:
先对数组排个序,先对所有负数取反,得到一个全是正数的数组
对于这个全是正数的数组,对数组中绝对值最小的那个元素取反即可
由于排序是直接默认升序排列而非按照绝对值排序,写获取绝对值最小元素时细节还挺多的
int largestSumAfterKNegations(vector<int>& nums, int k) {
std::sort(nums.begin(), nums.end());
// 先将所有负数取反
int i = 0;
for (; i < nums.size() && k > 0; ++i, --k) {
if (nums[i] < 0)
nums[i] *= -1;
else
break;
}
// 正数中只需要对最小的那个取反
if (k % 2 == 1) {
// 1、原数组中全是负数,都取反后k还没消耗完,对最后一个元素取反
if (i == nums.size())
nums[i - 1] *= -1;
// 2、原数组中全是正数,对第一个元素取反
// 3、原数组中有正有负,对绝对值最小的一个取反(i-1是原先绝对值最小的负数,i是原先绝对值最小的正数)
else if(i == 0 || nums[i] < nums[i - 1])
nums[i] *= -1;
else
nums[i - 1] *= -1;
}
int ans = 0;
for (int n : nums)
ans += n;
return ans;
}
134.加油站
这题的重点是抓住每个加油站的净加油量
思路:寻找一个加油站,该加油站前所有加油站的净加油量最小,从此处出发能实现“硬骨头放在最后啃”的效果
只改变出发站点的情况下,全程的净加油量是固定的。那么就能得出:如果一个站点之前的总净加油量越小,那么该站点之后的总净加油量就越大。
int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
int sum = 0;
int ans = 0;
int minSum = sum;
// 计算全程的净加油量
for (int i = 0; i < gas.size(); ++i) {
sum += gas[i] - cost[i];
if (sum < minSum) {
ans = i + 1;
minSum = sum;
}
}
// 全程净加油量总和小于0说明一定跑不完全程
if (sum < 0)
return -1;
else
return ans;
}
135.分发糖果
想了半天好像能写出来但又死活写不出来 :(
正常按逻辑写有两个问题始终解决不了:
1、相邻评分不同时,差值不一定是1,如何确定到底差多少?
2、相邻评分相同时,更难判断,任意值都可以作为差值,得根据再相邻的情况进一步判断。
解析中把一个相邻问题拆成了与左比和与右比两个问题,分别解决再进行合并
本题的局部最优:一个小孩的糖果数和左边比符合条件,和右边比也符合条件
推导出的全局最优:所有小孩的糖果与左右比都符合条件
思路:分别处理与左边比的结果和与右边比的结果,再对两边的结果进行合并
第一步:从前往后逐个获取与左对比的结果,如果评分比左边高,则糖果量比左多1,评分低则糖果量不变
第二步:从后往前逐个获取与右对比的结果,如果评分比右边高,则糖果量比右多1,评分低则糖果量不变
第三步:左右的结果中取糖果量较大的一个(兼容两个结果)
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] = std::max(candy[i + 1] + 1, candy[i]);
}
int ans = 0;
for (int n : candy)
ans += n;
return ans;
}