代码随想录算法训练营Day34|LC1005 K次取反后最大化的数组和&LC134 加油站&LC135 分发糖果

一句话总结:找到窍门答对一半。

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

先排序,然后对负值计数,之后对K与这个负值的进行判断,对不同情况进行分类再求和计算答案。

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        int n = nums.length;
        Arrays.sort(nums);
        int ans = 0;
        int cntNegative = 0;
        for (int i = 0; i < n; ++i) {
            if (nums[i] <= 0) cntNegative++;
        }
        if (cntNegative >= k) {
            for (int i = 0; i < k; ++i) {
                ans -= nums[i];
            }
            for (int i = k; i < n; ++i) {
                ans += nums[i];
            }
            return ans;
        } else {
            for (int i = 0; i < cntNegative; ++i) {
                nums[i] = -nums[i];
            }
            Arrays.sort(nums);
            for (int i = 0; i < k - cntNegative; ++i) {
                nums[0] = -nums[0];
            }
            for (int x : nums) ans += x;
            return ans;
        }
    }
}

还有一种利用哈希表的解法,思想大致一样,但少了额外排序的时间,因此时间复杂度更低。解法来源于0ms版本。

class Solution {
    public int largestSumAfterKNegations(int[] nums, int k) {
        int[] arr = new int[201];//hash表,这道题的范围是-100到100,正好需要201个位置存储。下标0表示-100
        int sum = 0;//保存当前nums数组的和
        for(int n : nums){
            arr[n+100]++;//统计元素出现次数
            sum += n;//统计当前所有元素的和
        }
        for(int i = 0; i < 100 && k > 0; i++){//从小到大遍历hash表中的负数
            if(arr[i] != 0){//如果当前数字还有剩余
                //如果当前数字i出现次数 < k ,则获取i的出现次数
                //如果当前数字i的出现次数 > k, 则获取k,表示剩余可以取负的次数
                int min = Math.min(arr[i],k);//获取当前数字的出现次数和k,较小的一个
                k -= min;//对当前数字i,每一个都取负,k表示可取负的次数,需要对min个i取负
                //负数取负后,变为正数,i = 0表示的是-100,取负变为100,应该存储在i = 200的位置,
                //i = 200表示的是正100
                arr[200-i] += min;//对min个i取负,则变为min个正i。存放到相应位置
                sum += (200-2*i)*min;//
            }
        }
        if(k % 2 != 0){
            for(int i = 100; i <= 200; i++){
                if(arr[i] != 0){
                    sum -= (i-100)*2;
                    return sum;
                }
            }
        }
        return sum;
    }
}

原题链接:134 加油站

 该算法思想符合贪心。一次遍历数组,找到其中累计可加油量减去与此同时路上耗费油量的最大差值,该位置一定要放在最后一段走,是为贪心思想,而需要返回的即是该位置的后一个位置,从该位置出发可保证。同时设置rem计算总油量与耗费的差值,小于0即说明永远到不了终点,返回-1。

class Solution {
    public int canCompleteCircuit(int[] gas, int[] cost) {
        int n = gas.length;
        int rem = 0;
        int minGas = Integer.MAX_VALUE;
        int minIndex = 0;
        for (int i = 0; i < n; i++) {
            rem += gas[i] - cost[i];
            if (rem < minGas) {
                minGas = rem;
                minIndex = i;
            }
        }
        if (minGas > 0) return 0;
        return rem < 0 ? -1 : (minIndex + 1) % n;
    }
}

 原题链接:135 分发糖果

利用一个数组left计算从左边来看应当给多少糖果,即如果ratings[i] > ratings[i - 1]即使得left[i] = left[i - 1]  +1,否则left[i] = 1。然后再遍历一遍数组,一边遍历一遍计算右值,最后答案即是left[i]和right的较大者。

class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int[] left = new int[n];
        for (int i = 0; i < n; ++i) {
            if (i > 0 && ratings[i] > ratings[i - 1]) left[i] = left[i - 1] + 1;
            else left[i] = 1;
        }
        int right = 0, ans = 0;
        for (int i = n - 1; i >= 0; --i) {
            if (i < n - 1 && ratings[i] > ratings[i + 1]) right++;
            else right = 1;
            ans += Math.max(left[i], right);
        }
        return ans;
    }
}

另有更精彩的解法。 

代码如下: 

class Solution {
    public int candy(int[] ratings) {
        int n = ratings.length;
        int ret = 1;
        int inc = 1, dec = 0, pre = 1;
        for (int i = 1; i < n; i++) {
            if (ratings[i] >= ratings[i - 1]) {
                dec = 0;
                pre = ratings[i] == ratings[i - 1] ? 1 : pre + 1;
                ret += pre;
                inc = pre;
            } else {
                dec++;
                if (dec == inc) {
                    dec++;
                }
                ret += dec;
                pre = 1;
            }
        }
        return ret;
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/candy/solutions/533150/fen-fa-tang-guo-by-leetcode-solution-f01p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值