当前位置: 首页 > news >正文

[leetcode 315] 计算右侧小于当前元素的个数

题目: https://leetcode.cn/problems/count-of-smaller-numbers-after-self/description/

在这里插入图片描述

暴力 for 循环肯定会超时。

第一种标准解法是归并排序,但是这样依旧超时😨

class Solution {
public:
    vector<int> counts;
    vector<int> index;
    vector<int> tmpIndex;
    void merge_sort(vector<int>& nums, vector<int>& tmp, int start, int end) {
        if (start >= end) {
            return ;
        }
        int mid = (start + end) / 2;
        int start1 = start, end1 = mid;
        int start2 = mid+1, end2 = end;
        merge_sort(nums, tmp, start1, end1);
        merge_sort(nums, tmp, start2, end2);
        int i = start1, j = start2, k = start;
        while (i <= end1 && j <= end2) {
            if (nums[i] <= nums[j]) {
                tmpIndex[k] = index[i];
                tmp[k++] = nums[i++];
            }
            else {
                tmpIndex[k] = index[j];
                tmp[k++] = nums[j++];
                for (int n = i; n <= end1; n++) {
                    counts[index[n]]++;
                }
            }
        }
        while (i <= end1) {
            tmpIndex[k] = index[i];
            tmp[k++] = nums[i++];
        }
        while (j <= end2) {
            tmpIndex[k] = index[j];
            tmp[k++] = nums[j++];
        }
        for (int n = start; n <= end; n++) {
            nums[n] = tmp[n];
            index[n] = tmpIndex[n];
        }
    }
    vector<int> countSmaller(vector<int>& nums) {
        int len = nums.size();
        vector<int> tmp(len);
        counts = vector<int>(len, 0);
        index = vector<int>(len);
        tmpIndex = vector<int>(len);
        for (int i = 0; i < len; i++) {
            index[i] = i;
        }
        merge_sort(nums, tmp, 0, len-1);
        return counts;
    }
};

其实完全可以只排列下标,像下面这样(不过依旧超时)

class Solution {
public:
    vector<int> counts;
    vector<int> index;
    vector<int> tmpIndex;
    void merge_sort(vector<int>& nums, int start, int end) {
        if (start >= end) {
            return ;
        }
        int mid = (start + end) / 2;
        int start1 = start, end1 = mid;
        int start2 = mid+1, end2 = end;
        merge_sort(nums, start1, end1);
        merge_sort(nums, start2, end2);
        int i = start1, j = start2, k = start;
        while (i <= end1 && j <= end2) {
            if (nums[index[i]] <= nums[index[j]]) {
                tmpIndex[k++] = index[i++];
            }
            else {
                tmpIndex[k++] = index[j++];
                for (int n = i; n <= end1; n++) {
                    counts[index[n]]++;
                }
            }
        }
        while (i <= end1) {
            tmpIndex[k++] = index[i++];
        }
        while (j <= end2) {
            tmpIndex[k++] = index[j++];
        }
        for (int n = start; n <= end; n++) {
            index[n] = tmpIndex[n];
        }
    }
    vector<int> countSmaller(vector<int>& nums) {
        int len = nums.size();
        vector<int> tmp(len);
        counts = vector<int>(len, 0);
        index = vector<int>(len);
        tmpIndex = vector<int>(len);
        for (int i = 0; i < len; i++) {
            index[i] = i;
        }
        merge_sort(nums, 0, len-1);
        return counts;
    }
};

果然,还是要靠树状数组解决。树状数组参考这里:https://www.cnblogs.com/xenny/p/9739600.html

什么是树状数组?

在这里插入图片描述

黑色框是原数组 A,红色框是树状数组 C。树状数组存储了前缀和,关系是:

C[1] = A[1];
C[2] = A[1] + A[2];
C[3] = A[3];
C[4] = A[1] + A[2] + A[3] + A[4];
C[5] = A[5];
C[6] = A[5] + A[6];
C[7] = A[7];
C[8] = A[1] + A[2] + A[3] + A[4] + A[5] + A[6] + A[7] + A[8];

什么是 lowbit ?

对于 x&(-x),其结果为

  • x 为零,结果为零;
  • x 为奇数,结果为 1;
  • x 为偶数,且是 2 的幂,结果为 x;
  • x 为偶数,但不是 2 的幂,结果为 x 的因子中 2 的最大次方;

为什么树状数组的大小是 n+1 ?

因为 0 号位置不能用,0&(-0) = 0

class Tree {
public: 
    vector<int> tree;
    int n;
    Tree (int n_) : tree(vector<int>(n_+1,0)), n(n_) {}
    int lowbit(int x) {
        return x & (-x);
    }
    void update(int x) {
        while (x <= n) {
            ++tree[x];
            x += lowbit(x);
        }
    }
    int qurry(int x) {
        int ret = 0;
        while (x > 0) {
            ret += tree[x];
            x -= lowbit(x);
        }
        return ret;
    }
};

class Solution {
public:
    vector<int> countSmaller(vector<int>& nums) {
        int len = nums.size();
        vector<int> tmp(nums);
        sort(tmp.begin(), tmp.end());
        for (int& num : nums) {
            num = lower_bound(tmp.begin(), tmp.end(), num) - tmp.begin() + 1;
        }
        Tree tree(len);
        vector<int> ans(len);
        for (int i = len - 1; i >= 0; i--) {
            int x = nums[i];
            ans[i] = tree.qurry(x - 1);
            tree.update(x);
        }
        return ans;
    }
};

相关文章:

  • Linux服务器及应用环境快速部署、调试、迁移、维护、监控
  • sqli-labs靶场自动化利用工具——第1关
  • 跨国公司撤出背后的启示:中国IT产业的挑战与机遇
  • 架构师考试系列(1)论文专题:基于构件的软件开发方法
  • linux kernel 6.x 用户态地址空间探究
  • Linux grep筛选命令及管道符|详解
  • 【Docker 的安装:centos】
  • mbatis应用到的设计模式
  • 数据库 -neo4j的基本操作
  • 第二十篇-推荐-纯CPU(E5-2680)推理-llama.cpp-qwen1_5-72b-chat-q4_k_m.gguf
  • 校园微社区微信小程序源码/二手交易/兼职交友微信小程序源码
  • SD-WAN技术:优化国内外服务器访问的关键
  • ESP32中micro-ROS与ROS2通信(点亮esp32指示灯)
  • Shell ❀ 条件测试语句
  • Transforming the Latent Space of StyleGAN for Real Face Editing翻译
  • 导入shp数据到postgis库
  • plotly parallel_coordinates平行坐标可视化
  • 前端使用dockerfile生成镜像
  • pandas对于文件数据基本操作,数据处理常用
  • WebSocketSSE实时动态数据展示
  • 数字三渔冲:打造美丽乡村新范式
  • 【爬虫】JS逆向解决反爬问题系列3—sign破解
  • 算法day55|392,115
  • 1 安装部署
  • 提交 bug 的内容书写规范
  • 16含风光水的虚拟电厂与配电公司协调调度模型(场景削减MATLAB程序)
  • Linux中find用法示例
  • 能源监控管理系统|瑜岿科技
  • RV1126笔记五:人脸识别方案<三>
  • 基于Python的Flask WEB框架实现后台权限管理系统(含数据库),内容包含:用户管理、角色管理、资源管理和机构管理
  • MySQL面试常问问题(锁 + 事务) —— 赶快收藏
  • Java进阶—JUC编程