406. 根据身高重建队列 贪心想法加二分和树状数组的优化(sort重载)

在这里插入图片描述
在这里插入图片描述

如何排序:

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

我们先按从小到大来进行排列,当first相同时,second从大到小排列

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

对于目标数组设为res,预处理n个空间,这里n为上面的数组的大小n == 6,按照sort以后的数组,按该顺序依次插入
res的获得顺序为:

  1. [[],[],[],[],[4,4],[]]
  2. [[],[],[5,2],[],[4,4],[]]
  3. [[5,0],[],[5,2],[],[4,4],[]]
  4. [[5,0],[],[5,2],[6,1],[4,4],[]]
  5. [[5,0],[],[5,2],[6,1],[4,4],[7,1]]
  6. [[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

解释:
[4,4] 4肯定是最小的,所以插入的地方前面应该要有second个空余的位置,(空余位置插入后肯定比4大,所以满足要求)
[5][2] 5是第二小的,插入时前面要有second个空余位置
以此类推

如何判断前面空余位置有几个?每次插入到的位置,将那个位置置为1,如:

  1. [[],[],[],[],[4,4],[]]
    0,0,0,0,1,0
  2. [[],[],[5,2],[],[4,4],[]]
    0,0,1,0,1,0
    这样就可以使用前缀和来判断这个位置i之前有几个1,同时剩下几个0。

那这么每次插入都进行一次遍历并且要维护前缀和数组,时间复杂度O(n3);
考虑到插入时可以用二分的方法来进行优化,前缀和可以用树状数组来优化,时间复杂度O(n * log2n);

题目给的最大2000,暴力时间复杂度为6*109
优化后为 2000 * 12 * 12 约为 3 * 105
减少不是一点半点。

重载时:
引用传递的效率会更高,见435 无重叠区间

sort(people.begin(), people.end(), [](vector<int>a, vector<int>b) {
            if (a[0] != b[0]) return a[0] < b[0];
            else return a[1] > b[1];
        });
        
        //引用传递效率高
        sort(people.begin(), people.end(), [](vector<int>&a, vector<int>&b) {
            if (a[0] != b[0]) return a[0] < b[0];
            else return a[1] > b[1];
        });

code

class Solution {
public:
int n;
vector<int>tr;
vector<vector<int>> res;
    int lowbit(int x) {
        return x & (-x);
    }

    void add(int x, int v) {
        for (int i = x; i <= n; i += lowbit(i)) tr[i] += v;
    }

    int query(int x) {
        int res = 0;
        for (int i = x; i; i -= lowbit(i)) res += tr[i];
        return res;
    }

    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        n = people.size();
        sort(people.begin(), people.end(), [](vector<int>a, vector<int>b) {
            if (a[0] != b[0]) return a[0] < b[0];
            else return a[1] > b[1];
        });
        tr.resize(n + 1);
        res.resize(n);
        for (auto p : people) {
            int l = 0, r = n - 1;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (mid - query(mid + 1) >= p[1]) r = mid;
                else l = mid + 1;             
            }
            add(l + 1, 1);
            res[l] = p;
            
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,根据提供的引用内容,没有找到关于迪杰斯特拉算法树状数组优化的信息。但是,我可以为您介绍一下迪杰斯特拉算法和树状数组的基本概念和应。 迪杰斯特拉算法,也称为狄克斯特拉算法,是一种用于解决图中最短路径问题的算法。该算法的基本思想是从起点开始,逐扩展到距离起点更远的节点,直到到达终点为止。在扩展的过程中,通过比较不同路径的距离,选择距离最短的路径进行扩展,直到到达终点。 树状数组,也称为二叉索引树,是一种用于高效维护序列前缀和的数据结构。该数据结构可以在O(log n)的时间内完成单点修改和区间查询操作,因此被广泛应用于解决各种算法问题,如逆序对问题、区间最大值/最小值问题等。 虽然迪杰斯特拉算法和树状数组看似没有直接关系,但是在解决某些特定的问题时,两者可以结合使用,以达到更高效的解决方案。例如,在解决带权图最短路径问题时,可以使用迪杰斯特拉算法结合树状数组进行优化,以达到更快的计算速度。 具体来说,可以使用树状数组维护一个优先队列,用于存储当前已经扩展的节点和它们的距离。在每次扩展节点时,可以使用树状数组快速找到距离最小的节点,并将其从队列中删除。这样可以避免使用传统的堆数据结构,从而提高算法的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值