LeetCode_103_QueueReconstructionByHeight


1. question: 根据身高重建队列(中等)

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

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

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/queue-reconstruction-by-height

示例 1:

1
2
3
4
5
6
7
8
9
10
输入: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]] 是重新构造后的队列。

示例 2:

1
2
输入:people = [[6,0],[5,0],[4,0],[3,2],[2,2],[1,4]]
输出:[[4,0],[5,0],[2,2],[3,2],[1,4],[6,0]]

提示:

1
2
3
4
1 <= people.length <= 2000
0 <= hi <= 106
0 <= ki < people.length
题目数据确保队列可以被重建

2. answers

这道题不仔细分析还是比较容易模糊的。

这道题需要仔细阅读。将给定的数组重新排列,使其满足如下要求:

  1. 数组中每个元素表示一个人。
  2. 元素是二元组,第一个元素是身高,第二个元素是前面大于等于本人身高的人的个数。

给定的数组是打乱顺序的,因此本题就是还原为真正的数组,满足上面的要求。

首先不能简单地根据身高来排列,因为元组中的第二个元素可能不满足要求人数。也不能根据元组中的第二个元素来排列,因为身高可能也不满足要求。

仔细分析,可发现如下:

  1. 身高最高的人,所以该元组的第二个元素一定是0,无论其排放在哪个位置,都是满足要求的。
  2. 身高次高的人,第二个元素不一定是1,可以是[0, 1],如果是0,只需要其放在身高最高的人前面即可。
  3. 身高第三高的人,第二个元素的取值可以是[0, 1, 2],如果是0,只需要放在前两个高的人的前面即可。如果是1,则需放在第二个高的前面。
  4. …以此类推。

注意,上面第二个元素取值一定不会超过其范围,因为超过了之后,根本就没有比他大的更多人,肯定无法满足要求的。

所以说,在对身高矮的人排队时,一定是要知道身高高的人的顺序的。【更准确一点地说,身高矮的是依据第二个元素插入到已知的队列中的】

进一步说,身高高的人是很容易满足要求的。身高矮的人,则是依据第二个元素插入到队列中。(因为它们不会比身高高的人高,也就不会影响它们是否满足第二个元素)。所以,先按照身高对人进行降序排列。【对于身高相同的人,按照第二个元素进行升序排列,这样正好满足了第二个元素要求】。之后,从第二人开始,根据第二个元素的值,遍历前面的队列(是几,就插入到第几个元素的前面),插入到队列中。因为涉及到频繁的插入操作,似乎采用链表更加合适。

不难发现,其实本题的思路也是从两个维度来考虑的,首先根据身高进行排序。然后根据人数在上个排序的基础上再次排序。和分发糖果有点类似。

代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
public class Solution_0103 {

// 对人按照身高降序排序,如果身高相同,则按照第二元素升序排序
// 先采用冒泡排序吧,时间复杂度为O(n^2)
public List<int[]> sortQueue(int[][] people) {

int[] person;
List<int[]> list = new LinkedList<>();

for (int i = 0; i < people.length - 1; i++) {

for (int j = i + 1; j < people.length; j++) {

if(people[j][0] > people[i][0]) {

person = people[i];
people[i] = people[j];
people[j] = person;
}
else if(people[j][0] == people[i][0] && people[j][1] < people[i][1]) {
person = people[i];
people[i] = people[j];
people[j] = person;
}
}

int[] temp = {people[i][0], people[i][1]};
list.add(temp);
}

int[] fin = {people[people.length - 1][0], people[people.length - 1][1]};
list.add(fin);

return list;
}

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

// 对人按照身高降序排序,如果身高相同,则按照第二元素升序排序
List<int[]> list = sortQueue(people);

for (int i = 1; i < list.size(); i++) {

int[] map = list.get(i);
int pre = map[1];
if(pre < i) {

// 遍历,找到比他大的元素的个数的位置
for (int j = 0; j < i; j++) {

// 将其插入到满足要求的位置中。
if(pre == 0) {

// 删除该元素,并插入该元素
list.remove(i);
list.add(j, map);

break;
}

// 找到一个比他大的,就计数。
int[] temp = list.get(j);
if(temp[0] > map[0] || (temp[0] == map[0] && temp[1] < map[1])) pre--;
}
}
}

// 遍历map,重新对数组赋值
int index = 0;
int[][] result = new int[people.length][2];
for(int[] map: list) {

result[index][0] = map[0];
result[index][1] = map[1];

index++;
}


return result;
}

public static void main(String[] args) {
System.out.println();

// int[][] people = {{7,0},{4,4},{7,1},{5,0},{6,1},{5,2}};
int[][] people = {{6,0},{5,0},{4,0},{3,2},{2,2},{1,4}};

Solution_0103 s = new Solution_0103();

int[][] result = s.reconstructQueue(people);

for(int[] i: result)
System.out.print("[" + i[0] + "," + i[1] + "]" + "\t");
}
}

上面是自己想出来的代码。参考题解,其实也是这种思路,只不过代码更加简洁,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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. 备注

参考力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 (leetcode-cn.com)代码随想录 (programmercarl.com)


文章作者: 浮云
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 浮云 !
  目录