題目
在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。
示例
輸入: [7,5,6,4]
輸出: 5
限制
0 <= 數組長度 <= 50000
實現代碼(歸併算法)
public static void main(String[] args) {
int[] nums = new int[]{7,5,6,4};
System.out.println(reversePairs(nums));
}
/**
* 歸併排序算法
*
*執行用時 :
* 35 ms
* 內存消耗 :
* 48.7 MB
* @param nums
* @return
*/
public static int reversePairs(int[] nums) {
int len = nums.length;
//如果是長度小於2則沒有逆序對
if (len < 2) {
return 0;
}
//拷貝數組
int[] tmpNums = nums.clone();
//輔助臨時數組
int[] temp = new int[len];
return reversePairs(tmpNums, 0, len - 1, temp);
}
/**
* nums[left..right] 計算逆序對個數並且排序
*
* @param nums
* @param start
* @param end
* @param temp
* @return
*/
private static int reversePairs(int[] nums, int start, int end, int[] temp) {
//數組長度只有1的情況下則沒有逆序對
if (start == end) {
return 0;
}
//中間長度 (left+right)/2會有整型溢出問題
int mid = start + (end - start) / 2;
//左邊逆序對數量
int leftPairs = reversePairs(nums, start, mid, temp);
//右邊逆序對數量
int rightPairs = reversePairs(nums, mid + 1, end, temp);
//如果是已經有序了則返回左邊的+右邊的
if (nums[mid] <= nums[mid + 1]) {
return leftPairs + rightPairs;
}
//跨越區間逆序對計算
int crossPairs = mergeAndCount(nums, start, mid, end, temp);
return leftPairs + rightPairs + crossPairs;
}
/**
* nums[start..mid] 有序,nums[mid + 1..right] 有序
*
* @param nums
* @param start
* @param mid
* @param end
* @param temp
* @return
*/
private static int mergeAndCount(int[] nums, int start, int mid, int end, int[] temp) {
//拷貝 start到end數組到輔助數組
for (int i = start; i <= end; i++) {
temp[i] = nums[i];
}
//i, j兩位置的第一個元素
int i = start;
int j = mid + 1;
int count = 0;
for (int k = start; k <= end; k++) {
if (i == mid + 1) {//當i超出範圍[start..mid],j歸併
nums[k] = temp[j];
j++;
} else if (j == end + 1) {//當j超出範圍[mid+1..end],i歸併
nums[k] = temp[i];
i++;
} else if (temp[i] <= temp[j]) {//當i小於J i歸並回去
nums[k] = temp[i];
i++;
} else {//當j<i時 j歸並回去 並且計數
nums[k] = temp[j];
j++;
//計數
count += (mid - i + 1);
}
}
return count;
}
如果大家對java架構相關感興趣,可以關注下面公衆號,會持續更新java基礎面試題, netty, spring boot,spring cloud等系列文章,一系列乾貨隨時送達, 超神之路從此展開, BTAJ不再是夢想!