最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

【算法训练营day34】LeetCode1005. K次取反后最大化的数组和 LeetCode134. 加油站 LeetCode135. 分发糖果

来源:博客园

LeetCode1005. K次取反后最大化的数组和

题目链接:1005. K次取反后最大化的数组和


(资料图片)

独上高楼,望尽天涯路

思路对了,代码也ac了,但是代码太臃肿了。

class Solution {private:    int get_min_index(vector& nums) {        int min_value = INT32_MAX;        int min_index = 0;        for (int i = 0; i < nums.size(); i++) {            if (nums[i] < min_value) {                min_value = nums[i];                min_index = i;            }        }        return min_index;    }public:    int largestSumAfterKNegations(vector& nums, int k) {        int min_index = 0;        for (int i = 0; i < k; i++) {            min_index = get_min_index(nums);            nums[min_index] = -nums[min_index];        }        int sum = 0;        for (int i = 0; i < nums.size(); i++) {            sum += nums[i];        }        return sum;    }};

慕然回首,灯火阑珊处

  • 第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
  • 第二步:从前向后遍历,遇到负数将其变为正数,同时K--
  • 第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
  • 第四步:求和
class Solution {static bool cmp(int a, int b) {    return abs(a) > abs(b);}public:    int largestSumAfterKNegations(vector& 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 sum = 0;        for (int num : nums) { // 第四步            sum += num;        }        return sum;    }};

LeetCode134. 加油站

题目链接:134. 加油站

独上高楼,望尽天涯

没有太好的想法。

慕然回首,灯火阑珊

首先是暴力解法。

class Solution {public:    int canCompleteCircuit(vector& gas, vector& cost) {        for(int i = 0; i < cost.size(); i++) {            int rest = gas[i] - cost[i];            int index = (i + 1) % cost.size();            while (rest > 0 && index != i) {                rest += gas[index] - cost[index];                index = (index + 1) % cost.size();            }            if (rest >= 0 && index == i) {                return i;            }        }        return -1;    }};

然后是有点玄学的贪心的解法,还没有理解透彻,需要进一步消化。

class Solution {public:    int canCompleteCircuit(vector& gas, vector& 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) {   // 当前累加rest[i]和 curSum一旦小于0                start = i + 1;  // 起始位置更新为i+1                curSum = 0;     // curSum从0开始            }        }        if (totalSum < 0) return -1; // 说明怎么走都不可能跑一圈了        return start;    }};

LeetCode135. 分发糖果

题目链接:135. 分发糖果

独上高楼,望尽天涯

写了好半天也讨论不全所有情况,犯了一开始提醒过的“顾此失彼”的错误。

慕然回首,灯火阑珊

这道题目一定是要确定一边之后,再确定另一边,例如比较每一个孩子的左边,然后再比较右边,如果两边一起考虑一定会顾此失彼

先确定右边评分大于左边的情况(也就是从前向后遍历),此时局部最优:只要右边评分比左边大,右边的孩子就多一个糖果,全局最优:相邻的孩子中,评分高的右孩子获得比左边孩子更多的糖果。

再确定左孩子大于右孩子的情况(从后向前遍历),那么又要贪心了,局部最优:取candyVec[i + 1] + 1candyVec[i] 最大的糖果数量,保证第i个小孩的糖果数量既大于左边的也大于右边的。全局最优:相邻的孩子中,评分高的孩子获得更多的糖果。

这在leetcode上是一道困难的题目,其难点就在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。

那么本题我采用了两次贪心的策略:

  • 一次是从左到右遍历,只比较右边孩子评分比左边大的情况。
  • 一次是从右到左遍历,只比较左边孩子评分比右边大的情况。

这样从局部最优推出了全局最优,即:相邻的孩子中,评分高的孩子获得更多的糖果。

class Solution {public:    int candy(vector& ratings) {        vector 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], candyVec[i + 1] + 1);            }        }        // 统计结果        int result = 0;        for (int i = 0; i < candyVec.size(); i++) {            result += candyVec[i];        }        return result;    }};

关键词: 灯火阑珊 独上高楼 顾此失彼