LeetCode 0406 根据身高重建队列

题目

假设有打乱顺序的一群人站成一个队列。 每个人由一个整数对(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]]

思路1(离散化+树状数组 非最优)

离散化+树状数组。

可以通过树状数组统计已经排好序的身高的情况,在新的样本进来的时候,可以快速统计比当前身高高的人的个数。会有很多个符合条件的样本,在其中选择身高最低的那一个加入已排序序列。

为什么选择身高最低的: 插入身高高的样本,后续身高第的样本都不符合条件。当前是n,插入后是n+1那后续这个样本不能被选择。

由于数组更新时间复杂度较高差点超时。

class BIT:
    def __init__(self, n):
        self.bit = [0] * (n + 1)

    def _low_bit(self, n):
        return n & -n
    
    def insert(self, n):
        while n < len(self.bit):
            self.bit[n] += 1
            n += self._low_bit(n)
    
    def query(self, n):
        ret = 0
        while n > 0:
            ret += self.bit[n]
            n -= self._low_bit(n)
        return ret

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        if not people:
            return []
        heights = set()
        for p in people:
            heights.add(p[0])
        heights = list(heights)
        heights.sort(reverse=True)
        d = {}
        for idx, val in enumerate(heights):
            d[val] = idx + 1
        n = len(heights)
        bit = BIT(n)
        ret = []
        indexs = set(range(len(people)))
        while indexs:
            select_idx = -1
            for idx in indexs:
                h, k = d[people[idx][0]], people[idx][1]
                if bit.query(h) == k:
                    if select_idx == -1 or people[select_idx][0] > people[idx][0]:
                        select_idx = idx
            indexs.remove(select_idx)
            ret.append(people[select_idx])
            bit.insert(d[people[select_idx][0]])
        return ret

思路二(排序+贪心)

按照身高有高到低排序,身高相同的话k由小到大排序

遍历数组,第i个人已知身高比他高的有k个人,那么他在当先排序数组的k+1个位置

class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        if not people:
            return []
        people.sort(key=lambda x:[-x[0], x[1]])
        ret = []
        for p in people:
            ret.insert(p[1], p)
        return ret
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值