1. 程式人生 > 實用技巧 >劍指offer-51 陣列中的逆序對

劍指offer-51 陣列中的逆序對

//在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個陣列中的逆序對的總數。
//暴力方法超時,考慮歸併排序
class
Solution { public int reversePairs(int[] nums) { if(nums==null||nums.length<2){ return 0; } int len=nums.length; int []copy=new int[len]; //通常輸入不許改變,複製一份 for
(int i=0;i<len;i++){ copy[i]=nums[i]; } //輔助陣列 int []temp=new int[len]; //歸併排序 return reversPairs(copy,0,len-1,temp); } public int reversPairs(int []nums,int left,int right,int []temp){ if(left==right){ return
0; } int mid=(left+right)/2; //左邊逆序數 int leftcount=reversPairs(nums,left,mid,temp); //右邊逆序數 int rightcount=reversPairs(nums,mid+1,right,temp); //如果左邊最後一個小於等於右邊第一個,因為左右都排序了,所以左邊全體小於右邊,沒有跨區間逆序數,直接返回兩邊的逆序數 if(nums[mid]<=nums[mid+1]){
return leftcount+rightcount; } //計算合併產生逆序數 int mergeCount=merge(nums,left,mid,right,temp); //返回兩邊+合併逆序數 return mergeCount+leftcount+rightcount; } public int merge(int []nums,int left,int mid,int right,int []temp){ for(int i=left;i<=right;i++){ temp[i]=nums[i]; } //i指標指向左半邊起始 int i=left; //j指標指向右半邊起始 int j=mid+1; int count=0; for(int k=left;k<=right;k++){ //左半邊遍歷完畢,把右半邊剩下的放入 if(i==mid+1){ nums[k]=temp[j]; j++; }else if(j==right+1){ //右半邊遍歷完畢,把左半邊剩下的放入 nums[k]=temp[i]; i++; }else if(temp[i]<=temp[j]){ //左邊指標位置小於右邊,不產生逆序數,直接把指標位置放回陣列,指標向前移動 nums[k]=temp[i]; i++; }else{ //右半邊指標位置較小,因為經過排序,那麼左半邊從i到末尾的mid的數全大於j位置的數,j位置逆序數為mid-i+1 //也就是i到mid全部數字個數 nums[k]=temp[j]; j++; count=count+(mid-i+1); } } return count; } }