剑指Offer---面试题36:数组中的逆序对
Posted 范二er
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指Offer---面试题36:数组中的逆序对相关的知识,希望对你有一定的参考价值。
一.题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。
例如:7,5,6,4,一共存在五个逆序对:7,5,7,6,7,4,5,4,6,4;
二.分析
思路1:显而易见,从头到尾扫描数组,没扫描到一个数字,就拿去和后面所有的数组进行比较,两个for
循环,解决问题,算法时间复杂度为o(n^2)
,
思路2:跳跃性的联想到merge_sort
,在merge
函数中,我们有一个过程是这样的,对左(leftArray)右(rightArray)两个已经排好序的数组进行整合,使整合之后的数组任然是排好序的,经典的算法思路如下:
[Merge Sort算法 浙江大学 陈越老师的视频,好的不要不要的
—出自中国大学MOOC网]
一个索引(leftstart)指向左边数组的第一位,一个索引(rightStart)指向右边数组的第一位,一个索引(tmpPos)指向临时的第一位
将左右侧数组索引所指向的位置处的数字进行比较,将小的数组存放进临时数组,然后相应的移动指针.
当
leftArray[leftStart]>rightArray[rightStart]
时,试想,leftArray
中的所有数字是不是都大于rightArray[rightStart]
???(因为leftArray
是排好序的),那么leftArray.length
也就统计了一次逆序对.当我们递归的过程进行完了,所有的逆序对也就统计完成了
经典归并排序的时间复杂度为0(nlogn)
四.代码
public class Solution
int count;
public int InversePairs(int[] array)
int n=array.length;
count = 0;
int[]tmpA=new int[n];
if (n != 0)
mergeSort(array,tmpA, 0, n - 1);
return count;
/**
* 归并排序--递归形式
*
* @param a 待排序的数组
* @param tmpA 临时创建的数组
* @param leftStart左边数组的起始位置
* @param rightEnd 右边数组的终止位置
* @author ZFY
*/
public void mergeSort(int[] a, int[] tmpA,int leftStart, int rightEnd)
if (leftStart>= rightEnd)
return;
int center = (leftStart+ rightEnd) /2;
mergeSort(a,tmpA, leftStart, center);//递归排序左边
mergeSort(a,tmpA, center + 1, rightEnd); //递归排序右边
merge(a,tmpA, leftStart, center+1, rightEnd);//归并
/**
* 归并过程 排序完成的序列在原序列a中
*
* @param a 待排序数组
* @param tmpA 临时数组
* @param leftStart 左边数组的起始位置
* @param rightStart 右边数组的起始位置
* @param rightEnd 右边数组的结束位置
* @author ZFY
*/
public void merge(int[] a,int[] tmpA, int leftStart, int rightStart, int rightEnd)
int leftEnd=rightStart-1;
int tmpPos = leftStart;
int eNum=rightEnd-leftStart+1;
while (leftStart <= leftEnd && rightStart <= rightEnd)
if (a[leftStart] <= a[rightStart])
tmpA[tmpPos++] = a[leftStart++];
else
tmpA[tmpPos++] = a[rightStart++];
count += leftEnd - leftStart + 1;
// 左右两侧的序列都是已经排好序的序列(递增),当左边的第一个数字大于右边第一个数字时
//那个左侧序列的所有数字都大于右边第一个
//例如: 4,5,6,7,8 3,4,5,6 左边的4大于右边的3,那么左侧所有的都大于3,
//左侧所有的个数为leftEnd - leftStart + 1;
while (leftStart <= leftEnd)
tmpA[tmpPos++] = a[leftStart++];
while (rightStart <= rightEnd)
tmpA[tmpPos++] = a[rightStart++];
for(int l=0;l<eNum;l++,rightEnd--)
a[rightEnd]=tmpA[rightEnd];
将第50行代码去掉,剩下的代码就是一个完整的归并排序的递归算法.排好序的数组任然存放于原数组array
中;
五.小结
由这个题目也可以看出来,归并排序算法说到底就是在消除序列中的逆序对,当序列中的逆序对为0的时候,这个序列就是已经被排好序了.
以上是关于剑指Offer---面试题36:数组中的逆序对的主要内容,如果未能解决你的问题,请参考以下文章