创作目的:为了方便自己后续复习重点,以及养成写博客的习惯。
思路:参考carl文档,自行模拟过程,使用贪心算法。
将数组按照绝对值大小从大到小排序,从前向后遍历,遇到负数将其变为正数,同时K--。如果K还大于0,那么反复转变数值最小的元素,将K用完。最后求和。
ledcode题目:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/
AC代码:
#define abs(a) (((a) > 0) ? (a) : (-(a)))
// 对数组求和
int sum(int *nums, int numsSize) {
int sum = 0;
int i;
for(i = 0; i < numsSize; ++i) {
sum += nums[i];
}
return sum;
}
int cmp(const void* v1, const void* v2) {
return abs(*(int*)v2) - abs(*(int*)v1);
}
int largestSumAfterKNegations(int* nums, int numsSize, int k){
qsort(nums, numsSize, sizeof(int), cmp);
int i;
for(i = 0; i < numsSize; ++i) {
// 遍历数组,若当前元素<0则将当前元素转变,k--
if(nums[i] < 0 && k > 0) {
nums[i] *= -1;
--k;
}
}
// 若遍历完数组后k还有剩余(此时所有元素应均为正),则将绝对值最小的元素nums[numsSize - 1]变为负
if(k % 2 == 1)
nums[numsSize - 1] *= -1;
return sum(nums, numsSize);
}
思路:参考carl文档,自行模拟过程,使用贪心算法。
首先如果总油量减去总消耗大于等于零那么一定可以跑完一圈,各个站点的加油站剩油量rest[i]相加一定是大于等于零的,每个加油站的剩余量rest[i]为gas[i] - cost[i]。i从0开始累加rest[i],和记为curSum,一旦curSum小于零,说明[0, i]区间都不能作为起始位置,因为这个区间选择任何一个位置作为起点,到i这里都会断油,那么起始位置从i+1算起,再从0计算curSum。
lecode题目:https://leetcode.cn/problems/gas-station/
AC代码:
int canCompleteCircuit(int* gas, int gasSize, int* cost, int costSize){
int curSum = 0;
int totalSum = 0;
int start = 0;
int i;
for(i = 0; i < gasSize; i++) {
// 当前i站中加油量与耗油量的差
int diff = gas[i] - cost[i];
curSum += diff;
totalSum += diff;
// 若0到i的加油量都为负,则开始位置应为i+1
if(curSum < 0) {
curSum = 0;
// 当i + 1 == gasSize时,totalSum < 0(此时i为gasSize - 1),油车不可能返回原点
start = i + 1;
}
}
// 若总和小于0,加油车无论如何都无法返回原点。返回-1
if(totalSum < 0)
return -1;
return start;
}
思路:参考carl文档,自行模拟过程,使用贪心算法。
首先明确两次贪心的策略:
一次是从左到右遍历,只比较右边孩子评分比左边大的情况。candyVec[i]与candyVec[i-1]比较。
一次是从右到左遍历,只比较左边孩子评分比右边大的情况。candyVec[i]与candyVec[i+1]比较。
取candyVec[i + 1] + 1 和 candyVec[i] 最大的糖果数量,candyVec[i]只有取最大的才能既保持对左边candyVec[i - 1]的糖果多,也比右边candyVec[i + 1]的糖果多。
ledcode题目:https://leetcode.cn/problems/candy/description/
AC代码:
#define max(a, b) (((a) > (b)) ? (a) : (b))
int *initCandyArr(int size) {
int *candyArr = (int*)malloc(sizeof(int) * size);
int i;
for(i = 0; i < size; ++i)
candyArr[i] = 1;
return candyArr;
}
int candy(int* ratings, int ratingsSize){
// 初始化数组,每个小孩开始至少有一颗糖
int *candyArr = initCandyArr(ratingsSize);
int i;
// 先判断右边是否比左边评分高。若是,右边孩子的糖果为左边孩子+1(candyArr[i] = candyArr[i - 1] + 1)
for(i = 1; i < ratingsSize; ++i) {
if(ratings[i] > ratings[i - 1])
candyArr[i] = candyArr[i - 1] + 1;
}
// 再判断左边评分是否比右边高。
// 若是,左边孩子糖果为右边孩子糖果+1/自己所持糖果最大值。(若糖果已经比右孩子+1多,则不需要更多糖果)
// 举例:ratings为[1, 2, 3, 1]。此时评分为3的孩子在判断右边比左边大后为3,虽然它比最末尾的1(ratings[3])大,但是candyArr[3]为1。所以不必更新candyArr[2]
for(i = ratingsSize - 2; i >= 0; --i) {
if(ratings[i] > ratings[i + 1])
candyArr[i] = max(candyArr[i], candyArr[i + 1] + 1);
}
// 求出糖果之和
int result = 0;
for(i = 0; i < ratingsSize; ++i) {
result += candyArr[i];
}
return result;
}
有时候坚持下去做某件事情可能并不一定能收到立杆见影的回报,但再坚持一下,也许结果就会不一样,加油。