zoukankan      html  css  js  c++  java
  • 剑指offer 51

    1 题目

    https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof

    2 题意

    在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

    示例 1:
    输入: [7,5,6,4]
    输出: 5
    

    3 思路

    author's blog == http://www.cnblogs.com/toulanboy/

    3.1 基础想法

    (1)本题要求的是逆序对,逆序对的定义题面已经给出。
    (2)而求逆序对的常见解法是借助归并排序来实现,更具体是借助他的merge过程

    3.2 归并排序求逆序对

    (1)归并逻辑

    我们知道,归并排序实际上分治的思想,归并排序的逻辑如下:

    • 其先将数组不断细分,最后细分到每个数组只有1个元素,那么这个只包含1个元素数组中就是有序的。
    • 然后将两个有序的长度为1的数组依次合并为长度为2的有序数组,后面合并过程就是依次类推,2合44合8,...,n/2合n

    (2)Merge过程

    值得注意的是:在上述的合并过程中,我们是可以得到其逆序对个数的?

    举个例子来说明合并过程:
    数组A: 11 22 33 44
    数组B: 12 20 55 66
    数组A和数组B合并为一个数组。
    正常做法是:分别用2个指针p1, p2指向A和B的第一个元素。然后进行两两对比,谁小谁下来放进新数组。
    

    进一步地,我们可以利用这个合并过程。若在上述例子中,p1指向22, p2指向20。那么可知p1 > p2,,们可知逆序对(22, 20),而且还可知道p1后面的数,都比20要大,所以可得到逆序对(33, 20)、(44, 20)。 故可得到的逆序对个数是p1后面剩余的元素个数。

    通过合并过程累加,就可以得到整个序列的逆序对。

    可能有同学想问:上述合并,只是得到了两个相对位置数组的逆序对,但逆序对个数还应该包括这个位置相对其他位置的逆序对,这部分是如何统计上去的?

    答:实际上,上述两个相对位置数组合并为1个大数组后,他必然会经历和前面大数组、后面大数组的过程,所以他前面的元素、他后面的元素相对他的逆序对个数也会被统计到的。

    4 代码

    //author's blog == http://www.cnblogs.com/toulanboy/
    class Solution {
    public:
        int ans = 0;
        vector<int> temp;//辅助数组,用来存储新的有序数组
        void fenzhi(vector<int>& nums, int left, int right){
            if(left >= right){
                return;
            }
            int mid = (left+right) >> 1;
            fenzhi(nums, left, mid);//拆分,得到左边
            fenzhi(nums, mid+1, right);//拆分,得到右边
            merge(nums, left, mid, right);//左右合并
        }
        void merge(vector<int>& nums, int left, int mid, int right){
            int p1 = left;
            int p2 = mid+1;
            temp.clear();
            while(p1 <= mid && p2 <= right){
                if(nums[p1] <= nums[p2]){
                    temp.push_back(nums[p1]);
                    p1++;
                }
                else{
                    temp.push_back(nums[p2]);
                    p2++;
                    ans += (mid-p1+1);
                }
            }
            while(p1 <= mid){
                temp.push_back(nums[p1]);
                p1++;
            }
            while(p2 <= right){
                temp.push_back(nums[p2]);
                p2++;
            }
            for(int i=0; i<temp.size(); ++i){
                nums[left+i] = temp[i];
            }
        }
    
        int reversePairs(vector<int>& nums) {
            fenzhi(nums, 0, nums.size()-1);
            return ans;
        }
    };
    
  • 相关阅读:
    MyEclipse10破解后续~~~~破解不成功
    Java分为三个体系JavaSE,JavaEE,JavaME 它们的区别以及java的各个版本?
    评分模型的检验方法和标准&信用评分及实现
    单点登录原理与简单实现
    MongoDB 3.2 从安装到使用。
    MongoDB笔记1:Windows下安装MongoDB
    MongoDB笔记2: MongoDB开启用户名密码验证
    MongoDB 官方C#驱动 封装 DbHelper
    五种开源协议的比较(BSD,Apache,GPL,LGPL,MIT)
    常用验证 正则表达式
  • 原文地址:https://www.cnblogs.com/toulanboy/p/13668699.html
Copyright © 2011-2022 走看看