# 406. Queue Reconstruction by Height

**<font color=red>难度: Medium</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/queue-reconstruction-by-height/description/

> 内容描述

```

Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue.

Note:
The number of people is less than 1,100.


Example

Input:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]

Output:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]
```

## 解题方案

> 思路 1
******- 时间复杂度: O(N^2)******- 空间复杂度: O(1)******

People are only counting (in their k-value) taller or equal-height others standing in front of them. 
So a smallest person is completely irrelevant for all taller ones. And of all smallest people, 
the one standing most in the back is even completely irrelevant for everybody else. Nobody is counting that person. 
So we can first arrange everybody else, ignoring that one person. And then just insert that person appropriately. 
Now note that while this person is irrelevant for everybody else, everybody else is relevant for this person - 
this person counts exactly everybody in front of them. So their count-value tells you exactly the index they must be standing.

So you can first solve the sub-problem with all but that one person and then just insert that person appropriately. 
And you can solve that sub-problem the same way, first solving the sub-sub-problem with all 
but the last-smallest person of the subproblem. And so on. The base case is when you have the sub-…-sub-problem of zero people. 
You’re then inserting the people in the reverse order, i.e., that overall last-smallest person in the very end 
and thus the first-tallest person in the very beginning. That’s what the above solution does, 
Sorting the people from the first-tallest to the last-smallest, and inserting them one by one as appropriate.

参考[stefan](https://leetcode.com/problems/queue-reconstruction-by-height/discuss/89359)

不算返回结果res的话，空间复杂度为O(1)

beats 99.12%

```python
class Solution(object):
    def reconstructQueue(self, people):
        """
        :type people: List[List[int]]
        :rtype: List[List[int]]
        """
        people.sort(key = lambda x: (-x[0], x[1]))
        res = []
        for p in people:
            res.insert(p[1], p)
        return res
```


> 思路 2
******- 时间复杂度: O(NlgN)******- 空间复杂度: O(2 ** (int(math.log(n, 2))+2)-1)******



思路一中每次insert都要shift后面所有的数字，所有总体时间复杂度是O(N^2)，我们可以对这里做一个优化


这一次排序我们先用h升序，再用k逆序，就是说h最小中k最大的人可以一下子就固定他的最终位置

- 比如说例子中[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]，
- 我们排序完就是[[4, 4], [5, 2], [5, 0], [6, 1], [7, 1], [7, 0]]
- 所以[4,4]就固定放在leaf层次的index为4的位置，[5,2]放在2的位置，，，然后[7,0]也想放在0的位置，但是index为0的位置被占了，
所以[7,0]就要放在所有没有被占的位置的第0个，这个占据的过程我们就可以用Binary Index Tree的leaf 层来实现，O(lgN)实现

参考[O(nlogn) - efficient indexing free slots](https://leetcode.com/problems/queue-reconstruction-by-height/discuss/89448/O(nlogn)-efficient-indexing-free-slots)


```python
class Solution:
    def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
        n = len(people)
        N = 1
        while N < n:
            N *= 2
        # tree = [0] * (2**(int(math.log(n, 2))+2)-1) # 或者直接用这个也可以
        tree= [0] * (2*N-1)
        i = 0
        while N > 0:
            tree[i:2*i+1] = [N] * (i+1)
            i= 2 * i + 1
            N //= 2

        def occupy(f, n=0): # 占据 f-th 位置: f -> [0, n-1]
            tree[n] -= 1
            if n >= len(tree)// 2:
                return n-len(tree)//2
            L = tree[2*n+1] 
            if f < L: # 前面剩余的位置不够了
                return occupy(f, 2*n+1)
            else:
                return occupy(f-L, 2*n+2)

        people.sort(key = lambda p: (p[0], -p[1]))
        queue = [0] * n
        for p in people:
            queue[occupy(p[1])] = p
        return queue
```



































