逆序数

作者: 徐凯_xp | 来源:发表于2018-04-29 13:05 被阅读11次

LeetCode 315. Count of Smaller Numbers After Self

很经典的一道题

已知数组nums,求新数组count,count[i]代表了在nums[i]右侧且比 nums[i]小的元素个数。
nums = [5, 2, 6, 1], count = [2, 1, 1, 0];
nums = [6, 6, 6, 1, 1, 1], count = [3, 3, 3, 0, 0, 0];
nums = [5, -7, 9, 1, 3, 5, -2, 1], count = [5, 0, 5, 1, 2, 2, 0, 0];

class Solution{
public:
    std::vector<int> countSmaller(std::vector<int> &nums);
};
思考与分析

最暴力的方法,即对每个元素扫描其右侧比它小的数,累加个数。假设数组元素 个数为N,算法复杂度 O(N^2)。
观察如下数组,该数组前4个元素有序,后4个元素有序,是否有更好的方法计算 count数组?
如果将这两段有序的数组归并为一个有序的数组,可否在归并排序时,将逆序数计 算出来?

算法设计

在归并该数组的前后两段有序数据时,即可将数组的全部逆序数计算出来,实际上,该数组 前半段有序数据有逆序数,后半段有序数据逆序数均为0。 在归并两段有序数据时,当需要将前一个数组元素的指针i指向的元素插入时,对应的count[i] ,即为指向后一个数组的指针j的值。
[图片上传失败...(image-af6ded-1524978344454)]



1.由于数组中的元素是随机的,一般不会分为前后两段有序的数据,如何在数据整体归并排 序时,计算出各个元素的逆序数?
2.由于归并排序时对原数组进行了排序,最终输出的count数组需要与原nums个数据对应起来, 如何解决?
解决方案

1.将元素nums[i]与元素的位置i绑定为pair,如<nums[i], i>,排序时,按照nums[i]的大小对 pair对进行排序,这样无论nums[i]如何排序,都知道nums[i]在原数组中的哪个位置。
2.利用pair对<nums[i], i>中的i对count[i]进行更新,任何一次子数组的归并,都可以认为是前 半段与后半段有序数组逆序数的计算,只需根据绑定的位置i将逆序数累加至count数组中。



#include<vector>
class Solution{
public:
    std::vector<int> countSmaller(std::vector<int> &nums){
        std::vector<std::pair<int,int>> vec;
        std::vector<int> count;
        for( int i = 0; i< nums.size();i++){
          vec.push_back(std::make_pair(nums[i],i));
          count.push_back(0);

         }
          merge_sort(vec,count);
          return count;
    }
private:
    void merge_sort_two_vec(std::vector<std::pair<int,int>> &sub_vec1,
      std::vector<std::pair<int,int>> &sub_vec2,
      std::vector<std::pair<int,int>> &vec,std::vector<int> &count){}
    void merge_sort(std::vector<std::pair<int,int>> &vec,std::vector<int> & count){
        if(vec.size() < 2){
            return;
        }
        int mid = vec.size() / 2;
        std::vector<std::pair<int,int>> sub_vec1;
        std::vector<std::pair<int,int>> sub_vec2;
        for(int i = 0; i < mid; i++){
            sub_vec1.push_back(vec[i]);
        }
        for(int i = mid; i< vec.size(); i++){
            sub_vec2.push_back(vec[i]);
        }
        merge_sort(sub_vec1, count);
        merge_sort(sub_vec2, count);
        vec.clear();
        merge_sort_two_vec(sub_vec1,sub_vec2,vec,count);
    }
};
void merge_sort_two_vec(std::vector<std::pair<int,int>> &sub_vec1,
      std::vector<std::pair<int,int>> &sub_vec2,
      std::vector<std::pair<int,int>> &vec,std::vector<int> &count){
    int i = 0;
    int j = 0;
    while(i < sub_vec1.size() && j < sub_vec2.size()){
        if(sub_vec1[i] .first< sub_vec2[j].first){
            count[sub_vec1[i].second] + = j;
            vec.push_back(sub_vec1[1]);
            i++;
        }
        else{
            sec.push_back(sub_vec2[j]);
            j++;
        }
    }
        for (; i<sub_vec1.size();i++){
            count[sub_vec1[i].second] += j;
            vec.push_back(sub_vec1[i]);

        }
        for(;j< sub_vec2.size();j++){
            vec.push_back(sub_vec2[j]);
        }

}

相关文章

  • 数据结构与算法 - 逆波兰表达式求值

    LeetCode 算法练习集合(Swift版)目录逆波兰表达式求值合并两个有序链表 <==> 类似于合并两个有序数...

  • 序数词(Ordinal Numbers)

    序数词(Ordinal Numbers) 序数词(Ordinal Numbers)汉语中表示为"第几" 有时,序数...

  • 时序数据库

    什么是时序数据库 简单来说时序数据库就是用来存储时序数据的数据库,而时序数据是基于时间一系列数据,一般来说时序数据...

  • 2020-2-16 刷题记录

    0X00 leetcode 刷题 7 道 搜索旋转排序数组(33) 搜索旋转排序数组 II(81) 寻找旋转排序数...

  • 归并排序

    在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序数对。一个排列中逆...

  • 周记 6.19 - 6.25

    时序数据库 时序数据库,简单的理解,就是按照时间来保存数据;例如,股票数据,温度.... 时序数据特点: 大量写入...

  • 算法入门(2)插入排序

    插入排序:就是把一个无序数组按照从小到大或者从大到小排序为有序数组。1.首先将无序数组中的第一个元素设为有序数组的...

  • leecode刷题(1)-- 删除排序数组中的重复项

    leecode刷题(1)-- 删除排序数组中的重复项 删除排序数组中的重复项 给定一个排序数组,你需要在原地删除重...

  • 剑指Offer Java版 面试题53:在排序数组中查找数字

    题目一:数字在排序数组中出现的次数。统计一个数字在排序数组中出现的次数。例如,输入排序数组{1, 2, 3, 3,...

  • 常见算法

    1. 将两个有序数组合成为一个有序数组

网友评论

    本文标题:逆序数

    本文链接:https://www.haomeiwen.com/subject/gnoglftx.html