leetcode 406. 根据身高重建队列(树状数组+倍增)

题目
poj1282
在这里插入图片描述
看到这道题我就知道我写过,但是我忘了。

  1. 我们直接的做法就是 从高到低排序,个子相同k从小到达排序,挨个放入vector里面,采用vector的insert插入到第几个数。。每次insert复杂度是o(n)。。
  2. 还有一种思路是 从低到高排序,格子相同k从大到小排序。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]想要前面有4个比他大的,所以[4,4]要放在第5个空格,-- – -- – [4,4] –
    [5,2]想要前面有2个比他大的,所以[5,2]要放在目前还剩空格的第3个空格,-- – [5,2] – [4,4] –
    [5,0]想要前面有0个比他大的,所以[5,0]要放在目前还剩空格的第1个空格,[5,0] – [5,2] – [4,4] –
    [6,1]想要前面有1个比他大的,所以[6,1]要放在目前还剩空格的第2个空格,[5,0] – [5,2] [6,1] [4,4] –
    [7,1]想要前面有1个比他大的,所以[7,1]要放在目前还剩空格的第2个空格,[5,0] – [5,2] [6,1] [4,4] [7,1]
    [7,0]想要前面有0个比他大的,所以[7,0]要放在目前还剩空格的第1个空格,[5,0] [7,0 [5,2] [6,1] [4,4] [7,1]
    为什么k要从大到小排序呢?
    我们看后两个[7,1] [7,0] 假如先将[7,0]放在剩余的第一个空格,[7,1]就要放在剩余的第二个空格,而放完[7,0]后只剩余1个空格了。。换而言之,谁先放,就代表它前面还有空格要求,[7,1]要求前面有1个空格,所以要比[7,0]先放。

现在已经转化为找第p[i][1]+1的空格问题了。每次找到后我们又要把这个空格置为非空,涉及到修改,我们就用树状数组来维护。如何找到第k个空格,可以二分+树状数组,也可以直接倍增。
下面就是倍增代码:res+1就是第k+1个空格。注意想要得到第x个空格,一定要query_Kth(x-1)。
因为我们只会 求 只包含x个空格的最远的长度。比如 [1,3],[1,5]包含x个空格,[1,6]包含x+1个空格,返回5.

    int query(int k){//放到第k个空格。
        --k;
        int res=0;
        for(int i=C;i>=0;--i)
            if(res+(1<<i)<MX&&k>=val[res+(1<<i)]) k-=val[res+=(1<<i)];
        add(res+1,-1);
        return res+1;//返回第k个空格的下标(从1开始)
    }
class Solution {
#define low(x) ((x)&(-x))
#define C 10
public:
    int MX,*val;
    void add(int x,int v){
        for(;x<MX;x+=low(x)) val[x]+=v;
    }
    int query(int k){//放到第k个空格。
        --k;
        int res=0;
        for(int i=C;i>=0;--i)
            if(res+(1<<i)<MX&&k>=val[res+(1<<i)]) k-=val[res+=(1<<i)];
        add(res+1,-1);
        return res+1;
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& a) {
        int n=a.size();MX=n+1,val=new int[MX];
        for(int i=1;i<=n;++i) val[i]=0;
        for(int i=1;i<=n;++i) add(i,1);
        sort(a.begin(),a.end(),[&](vector<int>&x,vector<int>&y)->bool{
            return (x[0]==y[0])?(x[1]>y[1]):(x[0]<y[0]);
        });
        vector<int>empty;
        vector<vector<int>>ans(n,empty);
        for(int i=0;i<n;++i) ans[query(a[i][1]+1)-1]=a[i];
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值