贪心难题

108 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第17天,点击查看活动详情

3.贪心难题

  • 此类题目如果从未见过,几乎不太可能独立思考出解决方案,需要多做多总结,甚至即使做过也会遗忘。
  • 贪心的难题往往代码很简洁,但是思路却非常难。

3.1.分发糖果

  • LeetCode 链接:leetcode.cn/problems/ca…

  • 难点在于贪心的策略,如果在考虑局部的时候想两边兼顾,就会顾此失彼。应分别考虑左侧大于右侧和右侧大于左侧的情况,分为两次遍历:

    • 第一次是正向遍历,只比较右边孩子评分比左边大的情况。
    • 第二次是反向遍历,只比较左边孩子评分比右边大的情况。如果此时也是正向遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果。
    class Solution {
        /**
             分两个阶段
             1、起点下标1从左往右,只要右边比左边大,右边的糖果 = 左边+1
             2、起点下标 ratings.length - 2 从右往左, 只要左边比右边大,
             	左边的糖果应该取本身的糖果数(符合比它左边大)和右边糖果数 + 1二者的最大值,这样才符合比它左边的大,也比它右边大
        */
        public int candy(int[] ratings) {
            int[] candyVec = new int[ratings.length];
            Arrays.fill(candyVec, 1);
            //第一次遍历,正向遍历
            for (int i = 1; i < ratings.length; i++) {
                if (ratings[i] > ratings[i - 1]) candyVec[i] = candyVec[i - 1] + 1;
            }
            //第二次遍历,反向遍历
            for (int i = ratings.length - 2; i >= 0; i--) {
                if (ratings[i] > ratings[i + 1]) candyVec[i] = Math.max(candyVec[i], candyVec[i + 1] + 1);
            }
            int ans = 0;
            for (int s : candyVec) {
                ans += s;
            }
            return ans;
        }
    }
    

3.2.根据身高重建队列

  • LeetCode 链接:leetcode.cn/problems/qu…

  • 与上述题目思路相同,一定要先考虑一个维度,确定好以后再解决另一个维度,如果两个维度一起考虑一定会顾此失彼,而本题中,如果优先按k考虑,会发现并不符合某个维度,从哪个角度来看都没确定下来,因此应优先确定身高降序排序,后续从高到矮按k插入指定索引处即可。

    class Solution {
        public int[][] reconstructQueue(int[][] people) {
            // 身高从大到小排(身高相同k小的站前面)
            Arrays.sort(people, (a, b) -> {
                if (a[0] == b[0]) return a[1] - b[1];
                return b[0] - a[0];
            });
            LinkedList<int[]> que = new LinkedList<>();
            for (int[] p : people) que.add(p[1],p);
            return que.toArray(new int[people.length][]);
        }
    }
    

3.3.跳跃游戏

  • LeetCode 链接:leetcode.cn/problems/ju…

  • 维护最远的距离值,与 数组长度 - 1 比较,符合条件返回 true。

    class Solution {
        public boolean canJump(int[] nums) {
            int ans = 0;
            for(int i = 0; i < nums.length - 1; i++){
                if(i <= ans) ans = Math.max(ans, i + nums[i]);
                else break;
                if(ans >= nums.length - 1) return true;
            }
            return ans >= nums.length - 1;
        }
    }