class Solution {
public:
vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
/*
1. Pick out tallest group of people and sort them in a subarray (S). Since there's no other groups of people taller than them, therefore each guy's index will be just as same as his k value.
2. For 2nd tallest group (and the rest), insert each one of them into (S) by k value. So on and so forth.
E.g.
input: [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
subarray after step 1: [[7,0], [7,1]]
subarray after step 2: [[7,0], [6,1], [7,1]]
*/
//把输入 优先按照 身高高的最前 然后如果身高相等的,则 k值小的在前的方式排序
sort(people.begin(), people.end(),[](const vector<int> &p1,const vector<int> &p2){
return p1[0] > p2[0] || (p1[0] == p2[0] && p1[1] < p2[1]);
});
vector<vector<int>> sol;
int n = people.size();
for (int i = 0; i < n;i++)
{
sol.insert(sol.begin() + people[i][1], people[i]);
}
return sol;
}
};
英文链接: https://leetcode.com/problems/queue-reconstruction-by-height/
中文描述: 假设有打乱顺序的一群人站成一个队列,数组
people
表示队列中一些人的属性(不一定按顺序)。每个people[i] = [hi, ki]
表示第i
个人的身高为hi
,前面 正好 有ki
个身高大于或等于hi
的人。请你重新构造并返回输入数组
people
所表示的队列。返回的队列应该格式化为数组queue
,其中queue[j] = [hj, kj]
是队列中第j
个人的属性(queue[0]
是排在队列前面的人)。示例 1:
示例 2:
提示:
大白话解释: 其实就是,有一个排好队的队伍,每个队伍的每个人有一个身高
h
。然后就可以知道每个人的前面,有多少身高大于等于ta的人数k
,即[h, k]
代表的含义。然后,把这个排好的队伍随机打散,就变成了题目里给的queue
数组。我们的任务是,根据queue
的内容,重新把各个元素按照原来的队伍顺序排好。解法1: 我们可以知道,最终重建好的队列,具有以下特征:
k
值的元素,必定h
值小的在前,h
值大的在后。设有A B两个人,他们具有相同的k
值,且ha >hb
,那么A一定在B后面。反证:如果A在B前面,A的前面有k个人身高大于等于A。B身高又小于等于A,那么B的k值至少也是ka+1
,A和B的k值一定不相等。然后就有了其实我也没完全想清楚为什么会正常工作的解法。。。当时是凭直觉猜的,这么着也许能行😂 那么这个神奇的方法如下:
k=1
的元素开始,获取该元素(current element)的特征(h值和k值)。这个例子里,是[6,1]元素。还是看代码吧,感觉还是看代码更好理解一些😂 代码:
复杂度分析: 时间复杂度: 一开始的排序,使用的是stl的sort函数,时间复杂度为O(nlogn)。 后面的共需要处理所有k>=1的元素;每个元素都要索引从0到该元素之间的元素来进行比较操作,虽然当k值条件满足之后,即可停止比较索引。然后还有后续的插入操作时,挪腾元素时的索引操作。是对插入位置到当前元素位置之间所有元素进行操作。比较索引和插入索引一起,正好是当前元素索引值的次数。所以,当输入的数组长度为n时,总的索引次数是1+2+3+...+n ,依等差数列求和公式,有n^2项,所以时间复杂度是O(n^2),所以总的时间复杂度是O(n^2) 空间复杂度: 由于一直是对给的数组进行操作,额外使用的只有一些数量固定的变量,所以空间复杂度为O(1)。
解法2: 从题目讨论帖子里看到的贼啦简洁的方法。属实把握了问题本质。 影响一个元素的k值的,只会是h值大于等于他的元素。所有h值小于他的元素,不论插在队伍的哪里,都不会影响其k值。 步骤
以上面的例1为例: 重排序后,数组变为 [[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]] 定义一个新的空数组A,然后[7,0]插入到A的0索引,A变为[[7,0]] [7,1]插入A的1索引处,A变为[[7,0],[7,1]] [6,1]插入A的1索引处,A变为[[7,0],[6,1],[7,1]] [5,0]插入A的0索引处,A变为[[5,0],[7,0],[6,1],[7,1]] [5,2]插入A的2索引处,A变为[[5,0],[7,0],[5,2],[6,1],[7,1]] [4,4]插入A的4索引处,A变为[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]
代码如下:
复杂度分析: 时间复杂度: 一开始的排序复杂度为O(nlogn)。后面,需要索引所有元素,然后又执行插入操作。每次插入操作的时间复杂度为O(M+N),其中M为要插入的元素,这里每次插入1个元素,即M=1. N为要移动的元素的数量,即从插入位置到当前数组的最后位置的元素个数。我们并不知道每个元素的插入位置,所以做最坏的估计,每次都从头插入,则每次插入时,时间复杂度为O(i),i为当前重排数组的大小。又需要插入n次,每次插入时,重排数组的长度递增,i也+1递增,总的时间复杂度依然是一个等差数列求和,也是O(n^2)。故总的时间复杂度为O(n^2)。 空间复杂度: 需要重新申请一个数组,存放重排后的队伍元素。空间复杂度为O(n)。