剑指offer | 统计数组中中的逆序对儿个数

 什么是逆序对儿?

    逆序对儿的定义为:在一个数组中,有两个数满足数组的下标满足i < j 时arr[i] > arr[j], 这样的一对儿数字称之为逆序对儿,再 为了有助于理解,再简单举个例子吧,有一数组arr中有四个元素,分别为7,4,8,6,那么7和4、7和6、8和6都是这个数组的逆序对儿,那么这个数组的逆序对儿个数就为3。那如何来求解他们的逆序对儿个数呢,请看下面的思路分析。

思路分析

   当 大家看到这个题的第一反应可能是使用穷举法,把数组所能够组成的对儿全部求解出来,然后进行判断,累加,这样求解的时间复杂度为O(n2),我们通过下面的例子来分析一下,有艺术组数组中的元素为7,5,6,2,我们可以采用分治的思想来求解,我们可以将这个数组拆分为两个长度为2的子数组,再把长度为2的子数组拆分为两个长度为1的子数组,{7}、{5}和{6}、{2},{7、5}和{6、2}都是逆序对儿,然后,我们再合并{7,5}和{6,2},再合并的同时统计逆序对儿的个数,由于我们已经统计了两个子数组内部的逆序对儿,所以我们应该对其进行排序,以免重复记录如下图分析:

通过上面的分析,大家应该会发现需找逆序对儿的过程很像归并排序,其实,在寻找逆序对儿个数的过程就是在归并排序的归并过程中对逆序对儿 进行统计即可。那么如何统计呢,思路如下图,还是使用上面的例子进行说明:

 

将{5、7}和{4,6}合并成一个数组并且统计逆序对儿的思路如下:P1指向的数字比P2指向的数字大, 那么P1指向的数字肯定比4 大,所以,逆序对儿+2,且将大的那个数字放入P3指向的位置,P1--,P3--,然后,然后,P1指向的数字比P2小,逆序对儿数不变,然后,将6放入数组中,P2--,再比较P1和P2指向的数字,逆序对儿数+1,将5放入数组中P3--,最后 再将4放入数组中。

代码实现

int InversePairCore(int *data,int *copy, int start, int end)
{
    
    if(start == end)
    {
        copy[start] = data[start];
        return 0;
    }
        int length = (end-start)/2;
        int left = InversePairCore(copy,data,start,start+length);
        int right = InversePairCore(copy,data,start+length+1,end);
      
        int i = start + length;
        int j = end;
        int indexCopy = end;
        int count = 0;
        while(i >= start && j >= start+length+1)
        {
          if(data[i] > data[j])
          {
              copy[indexCopy--] = data[i--];
              count += j - start -length; 
          }
          else
          {
             copy[indexCopy--] = data[j--];
          }        
        }
     for(;i >= start;--i)
     {
         copy[indexCopy--] = data[i]; 
     }
     for(;j >= start+length+1;--j)
     {
         copy[indexCopy--] = data[j];
     }
    return left + right + count;
}

int InversePairs(int *data, int length)
{
    if(data == NULL || length < 0)
    {
        return 0;
    }
    int *copy = (int *)malloc(sizeof(int) * length);
    assert(copy != NULL);
 


    int count = InversePairCore(data,copy,0,length-1);
    printf("数组排序后的结果为:");
    for(int i = 0;i < length;i++)
    {
        printf("%d ",copy[i]);
    }
    printf("\n");
    free(copy);
    return count;
}

O了

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值