LeetCode 406.根据身高重建队列

135 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目:给定一个数组people,其中people[i]=[hi,ki]people[i] = [h_i, k_i]表示第i个人的身高为hih_i 正好有kik_i个身高大于或等于hih_i的人,原始数组为乱序排列。要求重新构造队列。

解题思路

对于两个维度的数据,我们应该首先确定一个维度,之后在此基础上进行另一个维度的确定,在本题中,我们应该首先对身高进行从高到低的排序,如果身高相同,则按照另一个维度从大到小排序,最后遍历此数组,根据kk维度依次插入即可得到正确答案,注意此处为插入

为什么身高从高到低排序而不是从低到高:因为插入过程中高的先插入对低的没有影响,但低的对高的有影响。可得代码如下:

public int[][] reconstructQueue(int[][] people) {
    Arrays.sort(people, (p1, p2)->{
        if(p1[0]==p2[0]) return p1[1] - p2[1];
        return p2[0] - p1[0];
    });

    ArrayList<int[]> list = new ArrayList<>();
    for (int[] person : people) {
        list.add(person[1], person);
    }
    return list.toArray(new int[0][]);
}

时间复杂度为O(n2)O(n^2),空间复杂度为O(n)O(n)

LeetCode 135.分发糖果

我们可以再看一个和本题有点类似的题目:

n个孩子站成一排,给定一个ratings表示每个孩子的评分。要求按照以下标准给孩子分发糖果:

  1. 每个孩子至少一个糖果
  2. 相邻两个孩子评分更高的孩子会获得更多糖果

返回最少的糖果数目。

解题思路

本题可以从左到右得到局部最优解,再从右到左得到全局最优解,这个顺序是固定的。具体解题思路可看代码注释部分:

public int candy(int[] ratings) {
    int len = ratings.length;
    int[] candy = new int[len];
    for(int i=0;i<len;i++){
        // 每人先发一个糖
        candy[i] = 1;
    }

    for(int i=1;i<len;i++){
        // 如果后面的人分数比前面的高,比前面的多发一个糖
        // 保证了从左到右满足条件
        if(ratings[i]>ratings[i-1]) candy[i] = candy[i-1] + 1;
    }

    for(int j=len-2;j>=0;j--){
        // 如果前面的人分数比后面的高,则前面的要比后面的多一个糖
        // 但不能简单的等于后面的加一,因为前面的糖很可能已经大于后面的糖了(不能忽视第一次遍历的)
        // 例如 [1,3,4,5,2]
        // 前面的序列得到的糖果 [1, 2, 3, 4, 1]
        // 从后往前序列为 [1, 2, 3, 4, 1] 此处的4就维持不变
        if(ratings[j]>ratings[j+1]) candy[j] = Math.max(candy[j], candy[j+1] + 1);
    }

    int count = 0;
    for(int i=0;i<len;i++){
        count += candy[i];
    }

    return count;
}

时间复杂度为O(n)O(n)