前言:
今天借着这道题,又把归并排序算法学习了一下,总体来说收获还是挺大。
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数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(n2)。这种方法可以解决问题,但是不是很好。所以就要想别的办法。借鉴了别人的思路,发现可以用归并排序方法,稍微变一下型就可以。
一会我会先将归并排序算法贴出来。先说一下归并排序算法的基本思想吧,归并排序算法其实就是将整个数组进行分解,分解到每个子数组长度都为,然后在两两子数组进行排序,这样一直操作,直到等于数组长度,结束操作。归并排序算法的时间复杂度是O(nlogn)。这个是要比O(n2)好的。在这里推荐一篇关于归并排序算法的详细讲解的博客,讲的特别好,可以借鉴一下。归并排序算法博客。
上面只讲解了归并排序算法,下面我们就来说一说怎样利用排序算法来解决问题。我们在归并排序时,会分解到最后会是一个n个子数组,此时我们要进行两两排序,在排序比较的时候我们就可以找出逆序对。这里用两个指针p1、p2指向两个子数组的头部。然后进行比较如果此时第一个指针p1指向的数字大于p2指针指向的数字,就说明出现了逆序对。因为数组排好序的,所以p2指针到p1指针的数字都是大于p2指针的数字的,所以有几个数字就有几个逆序对,使用这样方法,就会找出所有的逆序对,并且不会出现漏的、重复的。
好啦不知道你们明白了没有,因为我这里不太会画图,所以只能口头描述了。如果没明白的,再看一看代码,相信你们会明白。
代码样例
归并排序
package com.asong.leetcode.InversePairsArray;
import sun.awt.image.PixelConverter;
/**
* 归并排序
*/
public class SortDemo {
public static void mergeSort(int[] array)
{
sort(array,0,array.length-1);
}
//递归分解
public static void sort(int[] array,int low,int high)
{
if(low==high)
{
return;
}
int mid = low + ((high - low) >> 1);
sort(array,low,mid);
sort(array,mid+1,high);
merge(array,low,mid,high);
}
//排序
public static void merge(int[] array,int low,int mid,int high)
{
//用于保存排序数组
int[] temp = new int[high-low+1];
int i = 0;
int p1 = low;
int p2 = mid+1;
//比较左右两部元素,那个小,把那个元素填入temp中
while(p1<=mid && p2 <= high)
{
temp[i++] = array[p1] < array[p2] ? array[p1++] : array[p2++];
}
//上面循环退出后,把剩余的元素依次填入到temp中
while(p1<=mid)
{
temp[i++] = array[p1++];
}
while(p2<=high)
{
temp[i++] = array[p2++];
}
//最终的排序结果复制给原数组
for (int j = 0; j < temp.length; j++) {
array[low+j] = temp[j];
}
}
public static void main(String[] args) {
int[] array = {8,1,3,6,2};
mergeSort(array);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
数组中的逆序对样例
package com.asong.leetcode.InversePairsArray;
import sun.awt.image.PixelConverter;
/**
* 归并排序
*/
public class SortDemo {
public static void mergeSort(int[] array)
{
sort(array,0,array.length-1);
}
//递归分解
public static void sort(int[] array,int low,int high)
{
if(low==high)
{
return;
}
int mid = low + ((high - low) >> 1);
sort(array,low,mid);
sort(array,mid+1,high);
merge(array,low,mid,high);
}
//排序
public static void merge(int[] array,int low,int mid,int high)
{
//用于保存排序数组
int[] temp = new int[high-low+1];
int i = 0;
int p1 = low;
int p2 = mid+1;
//比较左右两部元素,那个小,把那个元素填入temp中
while(p1<=mid && p2 <= high)
{
temp[i++] = array[p1] < array[p2] ? array[p1++] : array[p2++];
}
//上面循环退出后,把剩余的元素依次填入到temp中
while(p1<=mid)
{
temp[i++] = array[p1++];
}
while(p2<=high)
{
temp[i++] = array[p2++];
}
//最终的排序结果复制给原数组
for (int j = 0; j < temp.length; j++) {
array[low+j] = temp[j];
}
}
public static void main(String[] args) {
int[] array = {8,1,3,6,2};
mergeSort(array);
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}