代码随想录第二十九天(一刷&&C语言)|K次取反后最大化的数组和&&加油站&&分发糖果

创作目的:为了方便自己后续复习重点,以及养成写博客的习惯。

一、K次取反后最大化的数组和

思路:参考carl文档,自行模拟过程,使用贪心算法。

        将数组按照绝对值大小从大到小排序,从前向后遍历,遇到负数将其变为正数,同时K--。如果K还大于0,那么反复转变数值最小的元素,将K用完。最后求和。

ledcode题目:https://leetcode.cn/problems/maximize-sum-of-array-after-k-negations/

代码随想录第二十九天(一刷&&C语言)|K次取反后最大化的数组和&&加油站&&分发糖果_第1张图片

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/

代码随想录第二十九天(一刷&&C语言)|K次取反后最大化的数组和&&加油站&&分发糖果_第2张图片

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/

代码随想录第二十九天(一刷&&C语言)|K次取反后最大化的数组和&&加油站&&分发糖果_第3张图片

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;
}

全篇后记:

        有时候坚持下去做某件事情可能并不一定能收到立杆见影的回报,但再坚持一下,也许结果就会不一样,加油。

你可能感兴趣的:(Carl代码随想录练习记录,c语言,游戏,开发语言)