LeetCode 根据身高重建队列(406题)

LeetCode 根据身高重建队列

@author:Jingdai
@date:2021.03.18

题目描述(406题)

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

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

示例输入:

people = [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]

示例输出:

[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

解释:

编号为 0 的人身高为 5 ,没有身高更高或者相同的人排在他前面。
编号为 1 的人身高为 7 ,没有身高更高或者相同的人排在他前面。
编号为 2 的人身高为 5 ,有 2 个身高更高或者相同的人排在他前面,即编号为 0 和 1 的人。
编号为 3 的人身高为 6 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
编号为 4 的人身高为 4 ,有 4 个身高更高或者相同的人排在他前面,即编号为 0、1、2、3 的人。
编号为 5 的人身高为 7 ,有 1 个身高更高或者相同的人排在他前面,即编号为 1 的人。
因此 [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]] 是重新构造后的队列。

思路及代码

这个题目有两种解法,一个是先将原始数组 people 按身高降序排列后插入,二是根据原始数组 people 按身高升序排列后插入。

我们先不管排序后怎么做,先看看应该如何按身高降序或升序排列数组,如果身高不一样还好说,如果身高一样怎么升序或者降序排呢?这里注意到如果身高高的站前面,会影响后面的人,同时身高一样的人站前面也会影响后面的人,所以如果身高一样的话,我们可以认为站在前面的比站在后面的高一点,因为他们产生的结果是一样的。那 [5, 0][5, 1] 哪个在前呢?答案是 [5, 0],因为 [5, 0] 前面没有比他高或和他一样高的,而 [5, 1] 前面有一个,这里其实就是 [5, 0] ,所以肯定是 [5, 1] 在后面。所以如果身高 h 一样,那么 k 大的肯定就站在后面,而且前面已经分析了,站在后面的认为矮一点,即认为 h 相等的情况下 k 大的矮一点,根据此对原始数组排序。

方法1 身高降序排序

按照前面说明的排序方法进行降序排序,就是按 h 降序排序,当 h 相同时再按 k 的升序排序。

排完序之后我们将它们按顺序插入队列中,由于我们是按照身高降序排序的,所以后面插入元素的顺序不会影响到先插入的元素的 k 值,使其出错,所以我们在插入时只要按照自己的 k 值进行插入即可,k 等于几代表现在应该插入到第几个位置,现有的已插入元素都是比自己高的元素,所以直接插入即可。看下面的类似图演示。

原始people: [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
降序排序后 : [[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]
插入:       
           [[7,0]]
		   [[7,0],[7,1]]
           [[7,0],[6,1],[7,1]]
		   [[5,0],[7,0],[6,1],[7,1]]
		   [[5,0],[7,0],[5,2],[6,1],[7,1]]
		   [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

具体代码如下:

public int[][] reconstructQueue(int[][] people) {
    
    
    // height decrease
    Arrays.sort(people, (a,b) -> {
    
    
        if (a[0] != b[0]) {
    
    
            return b[0] - a[0];
        } else {
    
    
            return a[1] - b[1];
        }
    });

    LinkedList<int[]> queue = new LinkedList<>();
    for (int[] person : people) {
    
    
        int index = person[1];
        queue.add(index, person);
    }
    return queue.toArray(new int[queue.size()][]);
}

方法2 身高升序排序

同样按照前面说明的排序方法,这次进行身高升序排序,即按 h 升序排序,当 h 相同的时候按 k 降序排序。

排序完成后,按顺序插入到队列中,由于我们是按身高升序排列的,所以之后插入的元素都会比自己大,即影响自己的 k 值,而前面插入的元素没有影响。根据此,我们可以在每次插入元素时,根据自己 k 值在队列前面预留 k 个空的位置给后面的元素插入,因为后面插入的一定比自己高,所以可以满足要求,根据此插入完成。看下面的插入类似图演示。

原始people: [[7,0],[4,4],[7,1],[5,0],[6,1],[5,2]]
升序排序后 : [[4,4],[5,2],[5,0],[6,1],[7,1],[7,0]]
插入:       
           [ null, null, null, null,[4,4], null]
		   [ null, null,[5,2], null,[4,4], null]
           [[5,0], null,[5,2], null,[4,4], null]
           [[5,0], null,[5,2],[6,1],[4,4], null]
	       [[5,0], null,[5,2],[6,1],[4,4],[7,1]]
           [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

具体代码如下:

public int[][] reconstructQueue(int[][] people) {
    
    

    Arrays.sort(people, (a,b) -> {
    
    
        if (a[0] != b[0]) {
    
    
            return a[0] - b[0];
        } else {
    
    
            return b[1] - a[1];
        }
    });

    int[][] queue = new int[people.length][];

    for (int[] person : people) {
    
    
        int count = person[1];
        for (int i = 0; i < queue.length; i++) {
    
    
            if (queue[i] == null) {
    
    
                count--;
                if (count == -1) {
    
    
                    queue[i] = person;
                    break;
                }

            }
        }
    }
    return queue;
}

猜你喜欢

转载自blog.csdn.net/qq_41512783/article/details/114980444