题目: 给出一列数,a1, a2,....到 an,求它的逆序对数。逆序对就是 下标 i 比 j小,但是值 ai 却比 a j大。n 可以高大 10万。
思路:
(1)穷举,肯定不现实的,因为n 可以高达10万,肯定超时;
(2)考录分治法,受到归并排序的启发,能不能不断划分数组到最小,然后合并时统计 逆序对数。划分和递归都和归并排序没什么区别,问题在合并时如何统计。
合并左右两个数组时,左边 的数组的下标肯定要比右边数组的下标小,那么如果右边数组有比左边数组小的值,比如 [ 5,6] 和 [ 1 ] 合并,那么 5和6 肯定就是1的逆序对组合数了。因此,在每次把右边数组移入临时数组前,左边数组的个数就是该移入数的逆序对数。
代码:
/** * @author snail * @time 2014-9-11下午09:03:03 * TODO */ public class SecondMerge { private static int count = 0; //统计数组中的逆序对数 public static void main(String[] args) { int[] test = {1212,99,6,4}; SecondMerge.partition(test); System.out.println(count+"对 "); System.out.println(" "); for (int i : test) { System.out.print(i+" "); } } /** * decription: 划分 * @author : linjq */ private static void partition(int[] list){ int length = list.length; if (length <= 1) { return ; } int firstLength = length >> 1 ; int[] firstHalf = new int[firstLength]; System.arraycopy(list,0,firstHalf,0,firstLength); //继续二分 partition(firstHalf); int secondLength = length - firstLength; int[] secondHalf = new int[secondLength]; System.arraycopy(list,firstLength,secondHalf,0,secondLength); partition(secondHalf); //合并 int[] resultList = merge(firstHalf,secondHalf); System.arraycopy(resultList,0,list,0,resultList.length); } /** * decription:合并 * @author : linjq */ private static int[] merge(int[] firstList,int[] secondList){ int firstLength = firstList.length; int secondLength = secondList.length; int i = 0,j=0,k=0; int[] resultList = new int[firstLength + secondLength]; while( i<firstLength && j < secondLength ){ if(firstList[i] < secondList[j]){ resultList[k++] = firstList[i++]; }else{ //此时,左边还没来得及复制到临时数组中的元素,就是下标比右边小,值却比右边大的逆序值 count += (firstLength -i); resultList[k++] = secondList[j++]; } } while(i<firstLength){ resultList[k++] = firstList[i++]; } while(j < secondLength){ resultList[k++] = secondList[j++]; } return resultList; } }
时间: 2024-10-20 17:25:17