假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(h, k)表示,其中h是这个人的身高,k是排在这个人前面且身高大于或等于h的人数。
编写一个算法来重建这个队列。注意: 总人数少于1100人。
示例
输入:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
输出:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/queue-reconstruction-by-height
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
没有思路去看答案了…
循序渐进的思路
如果我们拿到的是一个没有重复身高的,按身高升序排列的数组我们应该怎么办?结果数组一开始为空,一个一个往里扔。那我们知道,当我们再往里扔一个人(身高为h,前方比他高的有k个)的时候,已经在数组里的都比我矮,不能算比我高的计数;之后往里扔的都比我高,一定会算作计数,那我只需要在前方有k给空位就好了,这样可以在O(n2)的时间完成目标
有身高相同的人会带来什么不同?
那样就不仅仅是前面的空位,前面的和我身高一样的也会带来计数。
首先考虑,是否可能有两个身高相同,前方比他们高的人数也相同?简单反证法可知不可能。
这样在往里加的时候就可以从k最大的加起,k比他小,且身高相同的会加在它的左边,也会带来计数。如果先从k小的加起,在给k大的找位置的时候就需要将h相同的也加入计数了。代码:
class Solution {
public int[][] reconstructQueue(int[][] people) {
//看题解看明白
int n = people.length;
int[][] ret = new int[n][];
Arrays.sort(people, (a, b) -> a[0]- b[0] == 0 ? b[1] -a[1] : a[0] - b[0]);//先按身高 再按比它高的数量升序排列
for(int i = 0; i < n;) {
int j = i + 1;
while(j < n && people[i][0] == people[j][0]) {
++j;//[i, j)的身高相同
}
while(i < j) {
int t = 0, index = 0;
while(t < people[i][1]) {
if(ret[index] == null) {
++t;
}
++index;
}
while(ret[index] != null) {
++index;
}
ret[index] = people[i];
++i;
}
}
return ret;
}
}
如果一开始数组降序排列呢?
那么在加一个人的时候,只要看当前队列里有多少人就好了。这时候身高相同的需要升序排列,否则后加的会影响先加的。代码:
class Solution {
public int[][] reconstructQueue(int[][] people) {
//看题解看明白
int n = people.length;
Arrays.sort(people, (a, b) -> a[0]- b[0] == 0 ? a[1] - b[1] : b[0] - a[0]);//先按身高降序 再按比它高的数量升序排列
ArrayList<int[]> ret = new ArrayList<>();
for(int[] p : people) {
ret.add(p[1], p);
}
for(int i = 0; i < n; ++i){
people[i] = ret.get(i);
}
return people;
}
}
java的ArrayList的add()似乎能够实现均摊O(1)的时间复杂度,也不知道怎么实现的
如果把均摊当O(1)的化这种方法是O(nlgn)(排序),比第一个快