【Javascript】贪心算法--分糖果问题、根据身高重建队列

贪心算法

贪心算法的本质就是选择每一阶段的局部最优!所以能够使用贪心的前提是能够通过局部最优推出最优,一个验证方法是通过举反例。

贪心算法的解题步骤

  • 将问题分解为若干个子问题
  • 找出适合的贪心策略
  • 求解每一个子问题的最优解
  • 将局部最优解叠成全局最优解

具体例子讲解

分发糖果

类似于接雨水问题

先计算出左边的落差(后一个比前一个高多少),然后再计算右边的落差(从右到左遍历,左边的比右边的高多少)。左右比较后取较高的。

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

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

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

代码实现:

var candy = function(ratings) {
    //我们先计算出左规则 left 数组,
    //在计算右规则的时候只需要用单个变量记录当前位置的右规则
    let len = ratings.length;
    let left = new Array(len + 1).fill(0);
    for (let i = 0; i < len; i++) {
        if (i > 0 && ratings[i] > ratings[i - 1] ) {
            left[i] = left[i - 1] + 1;
        }else {
            left[i] = 1;
        }
    }
    let right = 0;
    for (let j = len - 1; j >= 0; j--) {
        if (j < len - 1 && ratings[j] > ratings[j + 1]) {
            right++;
        }else {
            right = 1;
        }
        left[i] = Math.max(left[i], right);
    }
    return left.reduce((a, b) => a + b);

};

根据身高重建队列

假设有打乱顺序的一群人站成一个队列,数组 people 表示队列中一些人的属性(不一定按顺序)。每个 people[i] = [hi, ki] 表示第 i 个人的身高为 hi ,前面 正好 有 ki 个身高大于或等于 hi 的人。

请你重新构造并返回输入数组 people 所表示的队列。返回的队列应该格式化为数组 queue ,其中 queue[j] = [hj, kj] 是队列中第 j 个人的属性(queue[0] 是排在队列前面的人)。

思路分析

可以看到这个题目有两个维度需要比较,首先是身高hi,其次是ki指标。这种问题我们一定要分开考虑两个指标,不能同时考虑,容易顾此失彼。

那么就有两个问题,首先是应该顺序还是逆序考虑;第二个问题是应该先考虑身高还是先考虑ki。

如果先考虑ki的话,排出来的顺序完全没有按照身高,而且排序后的ki也不准确,所以肯定要先考虑身高,至少这样有一个维度是对的。由于ki是前面有ki个身高比自己大的,所以我们要先排个子高的,这样的ki也可以保证正确。

代码实现:

//根据身高重建队列
var reconstructQueue = function(people) {
    //若身高相同,则按照k来排序(从小到大)
    //若身高不同,则按身高从大到小排(这个很重要)
    let queue = [];
    people.sort((a, b) => {
        if(a[0] !== b[0]) {
            return b[0] - a[0];
        } else {
            return a[1] - b[1];
        }
    });
    for (let i = 0; i < people.length; i++){
        //精妙
        queue.splice(people[i][1], 0 , people[i]);
    }
    return queue;
};

未完待续,推荐大家跟着代码随想录刷题。Carl的思路真的很棒,而且总结的非常系统。不过做完一定要自己总结一下,或者画一下脑图奥!
学习参考

你可能感兴趣的:(算法,贪心算法,javascript,算法)