LeetCode 406 Queue Reconstruction by Height

20 篇文章 0 订阅

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

总结

第一种解法无论是在时间还是空间上都优于第二种,我在解题时从第一个元素的选取开始考虑,得到了第二种解法,尽管可行,但较为复杂。相比之下,第一种解法不仅简单而且更高效。文中如有不对或不恰当的地方,还请评论指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值