LeetCode 406 Queue Reconstruction by Height 题解
题意
给定一组数列,数列中每个元素为一对数(h, k),其中h表示该元素的值,k表示该元素之前所有元素中,值大于等于当前元素值的个数。这个数列被打乱了,要求重新排列这个数列使其正确。
思路
一 考虑最大元素
对于值为最大值的元素来说(可能多个),倘若将它们按照k从小到大排序,会发现他们的k值其实就是他们的下标。以样例 [[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]
来说,[7, 0], [7, 1]
两个元素即符合上面所述,k值即为下标。原因不难想到,对于值最大的元素来说,k即为前面的元素的个数。
进一步来说,对于次大元素 [6, 1]
,它的k值其实就是最大值排序之后,它所在的位置,即 [7, 0], [6, 1], [7, 0]
,原因同样,次大元素的k值本来就是大于等于它的元素个数,自然也就是下标了。
以此类推,按照h值从大到小,k值从小到大排序之后,将元素一个一个插入结果队列即可。
代码
class Solution {
public:
vector<pair<int, int>> reconstructQueue(vector<pair<int, int>> &people) {
sort(people.begin(), people.end(),
[](pair<int, int> a, pair<int, int> b) {
if (a.first == b.first)
return a.second < b.second;
return a.first >= b.first;
});
vector<pair<int, int>> res;
for (auto &&p : people) {
res.insert(res.begin() + p.second, p);
}
return res;
}
};
二 考虑最小元素
同样参考样例,对于正确顺序(即结果)的第一个元素来说 ,容易想到它应当是k为0中h最小的。选出第一个元素之后,将其他元素中,h值小于等于第一个元素的元素k值减一,就可以在子序列中重复上述过程,最终得到解。不过需要注意,在结果中应当将减去的值再加回来。即重复:取k为0且h最小元素 -> 放入结果队列 -> 其他h更小元素的k值-1 -> 继续去k为0且h最小元素…
代码(挺长的)
class Solution {
public:
vector<pair<int, int>> reconstructQueue_1(vector<pair<int, int>> &people) {
vector<pair<int, int>> res;
typedef pair<int, int> PII;
vector<pair<PII, int>> tmpP;
for (auto &&p : people) {
tmpP.push_back(pair<PII, int>(p, 0));
}
int sz = people.size();
for (int i = 0; i < sz; i++) {
int min_i = i;
for (int j = i; j < sz; j++) {
int jff = tmpP[j].first.first, jfs = tmpP[j].first.second;
int miff = tmpP[min_i].first.first,
mifs = tmpP[min_i].first.second;
if (jfs == 0 && (mifs != 0 || miff > jff))
min_i = j;
}
swap(tmpP[i], tmpP[min_i]);
PII tmp = tmpP[i].first;
tmp.second += tmpP[i].second;
res.push_back(tmp);
for (int j = i + 1; j < sz; j++) {
if (tmpP[j].first.first <= tmpP[i].first.first) {
tmpP[j].first.second -= 1;
tmpP[j].second += 1;
}
}
}
return res;
}
}
总结
第一种解法无论是在时间还是空间上都优于第二种,我在解题时从第一个元素的选取开始考虑,得到了第二种解法,尽管可行,但较为复杂。相比之下,第一种解法不仅简单而且更高效。文中如有不对或不恰当的地方,还请评论指正。