【剑指offer】面试题36:数组中的逆序对

题目:

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

思路:

归并排序的合并过程。主要是考虑合并两个有序序列时,计算逆序对数。

对于两个升序序列,设置两个下标:两个有序序列的末尾。每次比较两个末尾值,如果前末尾大于后末尾值,则有”后序列当前长度“个逆序对;否则不构成逆序对。然后把较大值拷贝到辅助数组的末尾,即最终要将两个有序序列合并到辅助数组并有序。

这样,每次在合并前,先递归地处理左半段、右半段,则左、右半段有序,且左右半段的逆序对数可得到,再计算左右半段合并时逆序对的个数。

总个数=左个数+右个数+左右合并时的个数

注意:

注意InversePairsCore形参的顺序是(data,copy),而递归调用时实参是(copy,data)。

要明白递归函数InversePairsCore的作用就行了,它是对data的左右半段进行合并,复制到辅助数组copy中有序。

最后,data和copy两个数组都是有序的。

代码:

class Solution {
public:
    int InversePairs(vector<int> data) {
        if(data.size()<=1)  return 0;

        vector<int>  copy(data);
        return InversePairsCore(data,copy,0,data.size()-1);
    }
private:
    int InversePairsCore(vector<int> &data,vector<int> &copy, int begin, int end)
    {//合并data的两半段到辅助数组copy中有序
        if(begin==end)
        {
            copy[end]=data[end];
            return 0;
        }
        else
        {
            int mid=begin+(end-begin)/2;

            int left=InversePairsCore(copy,data,begin,mid);//使data的左半段有序
            int right=InversePairsCore(copy,data,mid+1,end);//使data的右半段有序 

            int cnt=0;
            int cpIndex=end;
            int pre=mid;
            int post=end;
            //合并两个有序段,到copy数组
            while(pre>=begin && post>=mid+1)
            {
                if(data[pre]>data[post])//每次比较的是两个有序序列
                {
                    cnt=cnt+(post-mid-1+1);
                    copy[cpIndex--]=data[pre];
                    pre--;
                }
                else
                {
                    copy[cpIndex--]=data[post];
                    post--;
                }
            }

            for(;pre>=begin;--pre)
                copy[cpIndex--]=data[pre];
            for(;post>=mid+1;--post)
                copy[cpIndex--]=data[post];

            return left+right+cnt;
        }
    }
};
时间: 2024-11-08 07:45:02

【剑指offer】面试题36:数组中的逆序对的相关文章

剑指offer 面试题36—数组中的逆序对

题目: 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数.例如在数组{7,5,6,4}中一共存在5对逆序对,分别是(7,6),(7,5),(7,4),(6,4),(5,4) 基本思想: 解法一:O(n^2) 最简单的想法就是遍历每一个元素,让其与后面的元素对比,如果大于则count++,但是这样的时间复杂度是O(n^2). 解法二:O(nlogn) 归并排序思路: 例如7,5,4,6可以划分为两段7,5和4,6两个子数组 1

【剑指offer】题目36 数组中的逆序对

数组中任取两个数字,如果前面的数字大于后面的数字称为一个逆序对 如:1,2,1,2,1 有3个逆序对 思路:知道O(N2)肯定是错的.开始想hash,试图找到O(n)的算法,想了很久,找不到.后来想到排序,用原数组与排好序的数组对比,我写的快排,还是不对.想了几个小时,无奈看答案,原来是用变形的归并排序.排序真是博大精深,换个样子我就想不到了.... 在牛客网上AC的代码:脑子不清醒,各种小错,提交了好多遍. class Solution { public: void myMergeSort(v

剑指offer系列源码-数组中的逆序对

题目1348:数组中的逆序对 时间限制:1 秒内存限制:32 兆特殊判题:否提交:2133解决:500 题目描述: 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 输入: 每个测试案例包括两行: 第一行包含一个整数n,表示数组中的元素个数.其中1 <= n <= 10^5. 第二行包含n个整数,每个数组均为int类型. 输出: 对应每个测试案例,输出一个整数,表示数组中的逆序对的总数. 样例输入: 4 7 5 6 4

面试题36 数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 1 class Solution { 2 public: 3 int InversePairsCore(vector<int> &data,vector<int>&copy,int start,int end) 4 { 5 if(start==end) 6 { 7 copy[start]=data[start]; 8 return

剑指offer 面试题40—数组中两个只出现一次的数字

题目: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字.要求时间复杂度O(n),空间复杂度O(1). 基本思想: http://blog.csdn.net/wtyvhreal/article/details/44260321 #include <iostream> using namespace std; int Find1(int n)//从低位开始找第一个1的位置 { int index=0; while((n&1)==0 &&a

剑指Offer 面试题36:数组中的逆序对及其变形(Leetcode 315. Count of Smaller Numbers After Self)题解

剑指Offer 面试题36:数组中的逆序对 题目:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 例如, 在数组{7,5,6,4}中,一共存在5个逆序对,分别是(7,6),(7,5),(7,4),(6,4)和(5,4),输出5. 提交网址: http://www.nowcoder.com/practice/96bd6684e04a44eb80e6a68efc0ec6c5?tpId=13&tqId=11188 或 htt

剑指offer (36) 数组中的逆序对

题目:在数组中的两个数字如果前面一个数字大于后面一个数字,则这两个数字组成一个逆序对 题解分析: 首先应该想到很简单的一种解法,顺序遍历数组,对每个数,逐个比较该数字和其以后的数字,T(n) = O(n^2) (1)总体的意思就是将数组分成两段,首先求段内的逆序对数量,比如下面两段代码就是求左右两端数组段内的逆序对数量 count += Merge(data, temp, first, mid);//找左半段的逆序对数目 count += Merge(data, temp, mid + 1, e

【剑指offer】Q29:数组中出现次数超过一半的数字

就本题而言,个人觉得练习下partition函数是有必要的,毕竟它是快速排序的核心,是基础性的东西,也是必须要掌握的,至于书中给出的"取巧"性解法,是属于个人思维能力的考察,是一种考虑问题的思路,不是一两个问题就能练就的. partition函数,包括快速排序,是一定要信手拈来的,必须的. import random def MoreThanHalf(array): if len(array) == 0: return 0 start = 0 end = len(array) - 1

【剑指offer】二维数组中的查找

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 分析: 首先选择数组中右上角的数字.如果该数字等于要查找的数字,查找过程结束:如果该数字大于要查找的数字,剔除这个数字所在的列:如果该数字小于要查找的数字,剔除这个数字所在的行.依次类推,直到查找范围为空. 示例程序: #include <stdio.h> #include <stdlib.h> int

剑指OFFER之二维数组中的查找(九度OJ1384)

题目描述: 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 输入: 输入可能包含多个测试样例,对于每个测试案例, 输入的第一行为两个整数m和n(1<=m,n<=1000):代表将要输入的矩阵的行数和列数. 输入的第二行包括一个整数t(1<=t<=1000000):代表要查找的数字. 接下来的m行,每行有n个数,代表题目所给出的m行n列的矩阵(矩阵如题目描述所示,每