題目
在數組中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數。
示例 1:輸入: [7,5,6,4]
輸出: 5
限制:0 <= 數組長度 <= 50000
思路一:
暴力解題:依題意,我們可以用雙層for循環累計求和。
java代碼:
class Solution {
public int reversePairs(int[] nums){
int count = 0;
for(int i=0;i<nums.length-1;i++){
for(int j = i+1;j<nums.length;j++){
if(nums[i]>nums[j]){
count++;
}
}
}
return count;
}
}
這是一道面試題,答案不可能這麼簡單。運行後會發現,當數據過大,會超時。
此種方法被pass掉。
思路二:
爲了解決這個問題,我們需要設想這樣一個場景。
這道題是要我們輸出逆序數組對,那麼我們怎樣實現這個方式呢,答案是採用分而治之的思想,既然它要我們找逆序數對,我們不妨採用排序算法在排序過程中統計逆序數對。
歸併排序實現逆序數對的統計
首先,我們需要了解什麼是歸併排序,它的思想是什麼。
歸併排序是一種典型的分治策略。
它包含這樣三個步驟:
分解: 待排序的區間爲 l, r,令 m = (l+r)/2,我們把 l, r 分成 [l, m ]和 [m + 1, r],採用遞歸不斷分解。
解決: 使用歸併排序遞歸地排序兩個子序列
合併: 把兩個已經排好序的子序列 [l, m] 和 [m + 1, r] 合併起來
這裏借用網上的圖來給大家分析:
首先我們需要採用遞歸來把數組給劃分成最小單元。然後排序進行合併。
這裏我們對拆分的數組進行合併,原理是開闢一個新的數組,將分散的2個有序數組進行比較並存入新數組中,最後返回這個新數組。
瞭解了歸併排序,我們就可以在此基礎上對我們這一題進行求解。由圖我們可以看出,我們在合併的過程中進行統計逆序數對。只要第一個數組的元素大於第二個數組的元素,我們就可以進行統計。
統計公式爲:count = mid-i+1
java代碼:
public int reversePairs(int[] nums) {
int ret = 0;
int len = nums.length;
//判空操作
if(len<2){
return ret;
}
return mergeSort(nums, 0, nums.length - 1);
}
private int mergeSort(int[] nums, int left, int right) {
if (left >= right) {
return 0;
}
//拆分
int mid = (left+right)/2;
int leftPairs = mergeSort(nums, left, mid);
int rightPairs = mergeSort(nums, mid + 1, right);
//歸併
int crossPairs = merge(nums, left, mid, right);
//將歸併的所有結果彙總返回
return leftPairs+ rightPairs + crossPairs;
}
private int merge(int[] nums, int left, int mid, int right) {
//指向第一個數組指針
int i = left;
//指向第二個數組指針
int j = mid + 1;
int k = 0;
//計數
int count = 0;
//開闢新數組存放合併數組
int res[] = new int[right - left + 1];
//開始合併
while (i <= mid && j <= right) {
//如果j位置小於i位置,那麼j位置小於i位置後所有的左半邊的數
if (nums[i] > nums[j]) {
count += mid - i + 1;
res[k++] = nums[j++];
}else{
res[k++] = nums[i++];
}
// res[k++] = nums[i] <= nums[j] ? nums[i++] : nums[j++];
}
//合併剩下的數組
while (i <= mid) {
res[k++] = nums[i++];
}
while (j <= right) {
res[k++] = nums[j++];
}
//將值賦值回原數組
for (int m = 0; m < res.length; m++) {
nums[left + m] = res[m];
}
return count;
}
如若對此題還未理解,歡迎私信博主。或者是參考力扣官方題解:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/solution/shu-zu-zhong-de-ni-xu-dui-by-leetcode-solution/
歸併算法是一個經典算法,博主提醒小夥伴們務必掌握!