zoukankan      html  css  js  c++  java
  • 剑指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 };
  • 相关阅读:
    Java中break和continue跳出指定循环
    Linux命令对应英文全称
    linux 使用 rz 和 sz 命令
    linux tail命令的使用方法详解
    Linux常用命令大全(非常全!!!)
    正则 函数
    行级锁 java||数据库
    mysql插入操作跳过(ignore)、覆盖(replace into)、更新(on duplicate key)
    MYSQL 常用【函数】大全
    MySQL中INFORMATION_SCHEMA
  • 原文地址:https://www.cnblogs.com/zzw1024/p/11701321.html
Copyright © 2011-2022 走看看