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;
}