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

Posted zzw1024

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer——54数组中的逆序对相关的知识,希望对你有一定的参考价值。

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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

题解:
  这道题有待琢磨。。。
  
看到这个题目,我们的第一反应是顺序扫描整个数组。没扫描到一个数组的时候,逐个比较该数字和它后面的数字的大小。如果后面的数字比它小,则这两个数字就组成了一个逆序对。假设数组中含有n个数字。由于每个数字都要和O(n)这个数字比较,因此这个算法的时间复杂度为O(n^2)。
        我们以数组{7,5,6,4}为例来分析统计逆序对的过程。每次扫描到一个数字的时候,我们不拿ta和后面的每一个数字作比较,否则时间复杂度就是O(n^2),因此我们可以考虑先比较两个相邻的数字。
                                                     技术图片 
(a) 把长度为4的数组分解成两个长度为2的子数组;
(b) 把长度为2的数组分解成两个成都为1的子数组;
(c) 把长度为1的子数组 合并、排序并统计逆序对 ;
(d) 把长度为2的子数组合并、排序,并统计逆序对;
       在上图(a)和(b)中,我们先把数组分解成两个长度为2的子数组,再把这两个子数组分别拆成两个长度为1的子数组。接下来一边合并相邻的子数组,一边统计逆序对的数目。在第一对长度为1的子数组{7}、{5}中7大于5,因此(7,5)组成一个逆序对。同样在第二对长度为1的子数组{6}、{4}中也有逆序对(6,4)。由于我们已经统计了这两对子数组内部的逆序对,因此需要把这两对子数组 排序 如上图(c)所示, 以免在以后的统计过程中再重复统计。
      接下来我们统计两个长度为2的子数组子数组之间的逆序对。合并子数组并统计逆序对的过程如下图如下图所示。
      我们先用两个指针分别指向两个子数组的末尾,并每次比较两个指针指向的数字。如果第一个子数组中的数字大于第二个数组中的数字,则构成逆序对,并且逆序对的数目等于第二个子数组中剩余数字的个数,如下图(a)和(c)所示。如果第一个数组的数字小于或等于第二个数组中的数字,则不构成逆序对,如图b所示。每一次比较的时候,我们都把较大的数字从后面往前复制到一个辅助数组中,确保 辅助数组(记为copy) 中的数字是递增排序的。在把较大的数字复制到辅助数组之后,把对应的指针向前移动一位,接下来进行下一轮比较。
技术图片     

过程总结:

先把数组分隔成子数组,统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目。

 

  1 //最笨的方法
  2 class Solution01 {
  3 public:
  4     int InversePairs(vector<int> data) {
  5         if (data.size() < 2)return 0;
  6         set<int>s;
  7         s.insert(data[0]);
  8         int res = 0;
  9         for (int i = 1; i < data.size(); ++i)
 10         {
 11             if (data[i] < *(s.begin()))
 12                 res += s.size();
 13             else if (data[i] > *(--s.end()))
 14                 res += 0;
 15             else
 16             {
 17                 int k = 0;
 18                 for (auto ptr = s.begin(); ptr != s.end(); ++ptr, ++k)
 19                 {
 20                     if (*ptr > data[i])
 21                     {
 22                         res += s.size() - k;
 23                         break;
 24                     }
 25                 }
 26             }
 27             s.insert(data[i]);
 28         }
 29         return res;
 30     }
 31 };
 32 
 33 //书本代码,有点乱
 34 class Solution02 {
 35 public:
 36     int InversePairs(vector<int> data) {
 37         if (data.size() < 2)return 0;
 38         vector<int>v;//用来复制的
 39         v = data;
 40         return InversePairsCore(data, v, 0, data.size() - 1);
 41     }
 42 
 43     int InversePairsCore(vector<int>&data, vector<int>&copy, int start, int end)
 44     {
 45         if (start == end)
 46         {
 47             copy[start] = data[start];
 48             return 0;
 49         }
 50 
 51         int length = (end - start) / 2;
 52 
 53         int left = InversePairsCore(copy, data, start, start + length) % 1000000007;
 54         int right = InversePairsCore(copy, data, start + length + 1, end) % 1000000007;
 55 
 56         // i初始化为前半段最后一个数字的下标
 57         int i = start + length;
 58         // j初始化为后半段最后一个数字的下标
 59         int j = end;
 60         int indexCopy = end;
 61         int count = 0;
 62         while (i >= start && j >= start + length + 1)
 63         {
 64             if (data[i] > data[j])
 65             {
 66                 copy[indexCopy--] = data[i--];
 67                 count += j - start - length;
 68                 if (count >= 1000000007)//数值过大求余
 69                 {
 70                     count %= 1000000007;
 71                 }
 72             }
 73             else
 74             {
 75                 copy[indexCopy--] = data[j--];
 76             }
 77         }
 78 
 79         for (; i >= start; --i)
 80             copy[indexCopy--] = data[i];
 81 
 82         for (; j >= start + length + 1; --j)
 83             copy[indexCopy--] = data[j];
 84 
 85         return (left + right + count) % 1000000007;
 86     }
 87 };
 88 
 89 
 90 //使用归并排序思想
 91 class Solution03 {
 92 private:
 93     int count = 0;
 94 public:
 95     int InversePairs(vector<int> data) {
 96         if (data.size() < 2)return 0;
 97         mergeSort(data, 0, data.size() - 1);
 98         return count;
 99     }
100     void mergeSort(vector<int>&data, int L, int R)
101     {
102         if (L < R)
103         {
104             int M = (L + R) / 2;
105             mergeSort(data, L, M);
106             mergeSort(data, M + 1, R);
107             merge(data, L, M, R);
108         }
109     }
110     void merge(vector<int>&data, int L, int M, int R)
111     {
112         vector<int>temp(R - L + 1);
113         int t = R - L;
114         int tL = M;
115         int tR = R;
116         while (tL >= L && tR >= M + 1)
117         {
118             if (data[tL] > data[tR])
119             {
120                 count += tR - M;
121                 temp[t--] = data[tL--];
122                 count %= 1000000007;
123             }
124             else
125                 temp[t--] = data[tR--];
126         }
127         while (tL >= L)
128             temp[t--] = data[tL--];
129         while (tR >= M + 1)
130             temp[t--] = data[tR--];
131         for (int i = 0; i <= R - L; ++i)
132             data[L + i] = temp[i];
133     }
134 };

 

以上是关于剑指offer——54数组中的逆序对的主要内容,如果未能解决你的问题,请参考以下文章

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

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

剑指OFFER 数组中的逆序对

剑指 Offer 51. 数组中的逆序对

剑指offer-36:数组中的逆序对

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