剑指offer35:数组中的逆序对

1 题目描述

  在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

2 思路和方法

  利用归并排序的思想,先把数组分隔成子数组,先统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。注意在合并两个已排序的子数组后,要更新数组。O(n*log(n))。

3 C++核心代码

 1 class Solution {
 2 public:
 3     int InversePairs(vector<int> data) {
 4         if(data.size() <= 1)
 5             return 0;
 6         int count = 0;
 7         vector<int> copy(data); // 初始化
 8         InversePairsCore(data, copy, 0, data.size()-1,count);
 9         return count;
10     }
11
12     // 归并
13     void InversePairsCore(vector<int> &data, vector<int> &copy, int start, int end, int &count){
14         if(start>=end){
15             return;
16         }
17         int mid = (start + end) /2;
18         InversePairsCore(data,copy,start,mid,count);
19         InversePairsCore(data,copy,mid+1,end,count);
20
21         int copyIndex = end; // 将较大数字从后往前复制到辅助数组
22         int i = mid;    // 前半段最后一个元素下标
23         int j = end;    // 后半段最后一个元素下标
24         while (i>=start && j>=mid+1) {
25             if (data[j] < data[i]){     // 逆序
26                 count += j - mid;
27                 count %= 1000000007;    // 取模防止逆序对溢出
28                 copy[copyIndex--] = data[i--];
29             } else{
30                 copy[copyIndex--] = data[j--];
31             }
32         }
33
34         while (i>=start)
35             copy[copyIndex--] = data[i--];
36
37         while (j>=mid+1)
38             copy[copyIndex--] = data[j--];
39
40         for (int k = start; k <= end; ++k)
41             data[k] = copy[k];
42
43     }
44 };

4 C++完整代码

 1 #include<iostream>
 2 using namespace std;
 3 //数组中的逆序对
 4 long long GetMergePairsBetween(int* arr,int* copy,int start,int mid,int end)
 5 {
 6     //合并两个子数组,并计算逆序对个数
 7     int final1 = mid;//第一个数组的最后一位
 8     int final2 = end;//第二个数组的最后一位
 9     int index = end;//辅助数组的最后一位
10     long long count = 0;
11     while(final1 >= start && final2 >= mid+1)//两个数组都没有处理完
12     {
13        if(arr[final1] > arr[final2])
14        {
15            //如果第一个数组的元素大于第二个数组的任何元素,
16            //则第一个数组的元素一定大于第个数组中final2之前的所有元素
17            count += (final2 - mid);
18            //将final1处的元素拷贝至copy数组
19            //index和final1都向前移动
20            copy[index--] = arr[final1--];
21        }
22        else
23        {
24            //第一个数组的元素小于第二个数组的元素
25            //第二个数组的元素拷贝至copy数组
26            //并将index和final2前移
27            copy[index--] = arr[final2--];
28        }
29     }
30     while(final1 >= start)//第一个数组的元素没有处理完
31     {
32        copy[index--] = arr[final1--];
33     }
34     while(final2 >= mid + 1)//第一个数组的元素没有处理完
35     {
36        copy[index--] = arr[final2--];
37     }
38     for(int i = end; i > index;i--)
39         arr[i] = copy[i];
40     return count;
41 }
42 long long GetMergePairs(int* arr,int* copy,int start,int end)
43 {
44     long long ret = 0;
45     if(start < end)
46     {
47        int mid = start + ((end - start)>>1);
48        ret += GetMergePairs(arr,copy,start,mid);
49        ret += GetMergePairs(arr,copy,mid+1,end);
50        ret += GetMergePairsBetween(arr,copy,start,mid,end);
51     }
52     return ret;
53 }
54 long long GetTotalPairs(int arr[],int n)
55 {
56     if(arr == NULL || n < 2)
57        return 0;
58     int* copy = new int[n];
59     long long sum = GetMergePairs(arr,copy,0,n-1);
60     delete[] copy;
61     return sum;
62 }
63 int main()
64 {
65     int arr[] = {7,5,6,4};
66     int ret = GetTotalPairs(arr,sizeof(arr)/sizeof(arr[0]));
67     cout<<ret<<endl;
68     system("pause");
69     return 0;
70 }

参考资料

https://blog.csdn.net/zjwreal/article/details/88769617

https://blog.csdn.net/DERRANTCM/article/details/46761051(图)

https://blog.csdn.net/peiyao456/article/details/54645952(完整代码)

原文地址:https://www.cnblogs.com/wxwhnu/p/11421187.html

时间: 2024-11-08 07:45:37

剑指offer35:数组中的逆序对的相关文章

剑指offer 数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000000007 输入描述: 题目保证输入的数组中没有的相同的数字 数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5 示例1 输入 1,2,3,4,5,6,7,0 输出 7 思路:归并排序的思路.具体参考剑指

剑指offer_数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P. 并将P对1000000007取模的结果输出. 即输出P%1000000007 本题采用归并排序,归并排序算法我在前一篇博客里写到过,在那个基础上进行修改即可!(强烈建议先理解归并排序的具体算法后,再来做此题) public class Solution36 { private int count = 0; //记录次数 private int[] copy ;

剑指offer——数组中的逆序对

数组中的逆序对 **(不会)数据结构--小和问题 逆序对问题 原文地址:https://www.cnblogs.com/SkyeAngel/p/8978980.html

剑指Offer34 数组中的逆序对

1 /************************************************************************* 2 > File Name: 34_InversePairsInArray.c 3 > Author: Juntaran 4 > Mail: [email protected] 5 > Created Time: 2016年09月02日 星期五 20时05分05秒 6 *******************************

剑指offer-数组中的逆序对-数组-python

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000000007 输入描述: 题目保证输入的数组中没有的相同的数字 数据范围: 对于%50的数据,size<=10^4 对于%75的数据,size<=10^5 对于%100的数据,size<=2*10^5 class Solution: def InversePairs(self, data):

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

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

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

# @left part: [start, mid] # @right part: (mid, end] def merge(data, start, mid, end): if mid < start or end < mid: return 0 reverse = 0 ''' @ for start, it play as the start index of left part, and mid @ play as the end index of left part; @ mid +

剑指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

【Java】 剑指offer(51)数组中的逆序对

本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 在数组中的两个数字如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 思路 如果遍历数组,对每个数字都和后面的数字比较大小,时间复杂度为O(n^2),效率太低. 利用归并排序的思想,先将数组分解成为n个长度为1的子数组,然后进行两两合并同时排好顺序. 在对两个子区域合并排序时,记左边区域(下标为start~mid)的指针