题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
解题思路
我一看到这道题,首先就想到了冒泡排序,总是两两比较然后统计次数!
public class Sloution33 {
/**
* 冒泡解决问题
* @param array
* @return
*/
public int InversePairs(int[] array) {
int count=0;
for(int i=0;i<array.length;i++){
for(int j=i+1;j<array.length;j++){
if(array[i]>array[j]){
count++;
Swap(array[i], array[j]);
}
}
}
return count;
}
public void Swap(int a,int b){
int temp=a;
a=b;
b=temp;
}
}
但是上面的太耗时了效率n*n;
当时想过使用flag来表识,排好序的改进~但是这个题目不可以,排好序la,人家还是比你大~
后来看到大神使用归并排序,我自己也想了一下,反正我冒泡的思路也是排序,归并排序也是这样子弄 n*logN效率肯定不一样。用到了分而冶之的思路.
左边的逆序数,右边的逆序数。合并的逆序数
所以当前排好序的逆序数等于这三个部分组成的。
归并排序的三个要点:
1。首先分成小部分,不管排序。这个和快排不一样
2。分了之后,就是合并嘛,合并的时候处理顺序问题
就是这货,需要格外的空间处理
下面就是这个啦~
package JianzhiOffer;
public class Slution33_2 {
public int InversePairs(int[] array) {
int len = array.length;
if (len < 2)
return 0;
return mergeSort(array, 0, len - 1);
}
/**
* 归并排序,先分解,在合并
*
* @param array
* @param start
* @param end
* @return
*/
private int mergeSort(int[] array, int start, int end) {
// TODO Auto-generated method stub
if (start >= end) {
return 0;
}
int mid = start + (end - start) / 2;
/**
* 我们的数量等于左边+右边的数量在加上合并的数量,等于最后的数量
*/
int countL = mergeSort(array, start, mid);
int countR = mergeSort(array, mid + 1, end);
int arrayTemp[] = new int[end - start + 1];
/**
* 格外的空间,保存排好序的信息~
*/
for (int i = 0; i < arrayTemp.length; i++) {
arrayTemp[i] = 0;
}
int mergeCount = 0;
int iMid = mid;
int jEnd = end;
int kElementCount = end - start;
// 合并的操作
// satrt mid mid+1 end
// 前面半截有序的哦 有序的合并
while (iMid >= start && jEnd >= mid + 1) {
if (array[iMid] > array[jEnd]) {
mergeCount += (jEnd - mid);// 当前的比后面的都大从 mid+1 dao end
// 一共end-(mind+1)+1
arrayTemp[kElementCount] = array[iMid];// 保存最大的个
kElementCount--;
iMid--;
} else {
// 前面的元素没有后面的最大的大
arrayTemp[kElementCount] = array[jEnd];
kElementCount--;
jEnd--;
}
}
// 下面的可能单向的就完了,所以要排序的放入tmp中;
while (iMid >= start) {
arrayTemp[kElementCount] = array[iMid];
kElementCount--;
iMid--;
}
while (jEnd >= mid + 1) {
arrayTemp[kElementCount] = array[jEnd];
kElementCount--;
jEnd--;
}
/**
* 把排好序的赋值给我们的array
*/
for (int i = start, j = 0; i <= end; i++) {
array[start] = arrayTemp[j++];
}
/**
* 其实这里用到了分冶思想 我们的count=左边+右边+合并的数量; 这里处理的不错。就是个排序嘛~通过排序统计次数。直接就是合并排序
*/
return countL + countR + mergeCount;
}
}