劍指 Offer 51. 陣列中的逆序對
阿新 • • 發佈:2020-09-18
題目描述
在陣列中的兩個數字,如果前面一個數字大於後面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個陣列中的逆序對的總數。
示例1:
輸入: [7,5,6,4]
輸出: 5
限制:
0 <= 陣列長度 <= 50000
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof
思路解析
假設給定陣列為[8, 10, 15, 20, 70, 9, 25, 50, 60, 100]
,這個陣列的前一半和後一半都是有序的,那麼此時這個陣列的逆序對的個數應該如何統計?
指標i
指向[8, 10, 15, 20, 70]
j
指向[9, 25, 50, 60, 100]
首元素,比較var(i)
和var(j)
的大小。(這裡var(i)
和var(j)
指i
和j
指向元素的值)
- 若
var(i) < = var(j)
,則此時i
和j
指向元素不構成逆序對,否則構成逆序對(j++
); - 若
var(i) < = var(j)
,則代表後半段的陣列中,有j
個元素小於var(i)
;(這裡假設i
和j
均從0開始) - 由此可統計出前半段的陣列中每個元素所構成的逆序對的個數,且後半段陣列中不存在逆序對。
使用歸併排序的思想,當元素分組至每組僅有一個元素時,代表該組已經有序,返回此有序陣列中逆序對的個數為0,隨後進行歸併,並記錄每次歸併所產生的陣列的逆序對的個數。
時間複雜度\(O(n \log n)\)
程式碼實現
class Solution { private: vector<int> orderedArray; // From large to small public: int reversePairs(vector<int>& nums) { int n = nums.size(); vector<int> tmp(n); return mergeSort(nums, tmp, 0, n - 1); } int mergeSort(vector<int>& nums, vector<int>& tmp, int left, int right) { if(left >= right) return 0; int mid = (left + right) / 2; int prev_count = mergeSort(nums, tmp, left, mid) + mergeSort(nums, tmp, mid + 1, right); // Merge int i = left; int j = mid + 1; int curr_count = 0; int tmp_index = left; while(i <= mid && j <= right) { if(nums[i] <= nums[j]) { tmp[tmp_index] = nums[i++]; curr_count += (j - mid - 1); } else{ tmp[tmp_index] = nums[j++]; } tmp_index++; } while(i <= mid){ tmp[tmp_index++] = nums[i++]; curr_count += (j - mid - 1); } while(j <= right) tmp[tmp_index++] = nums[j++]; for(tmp_index = left; tmp_index <= right; tmp_index++) nums[tmp_index] = tmp[tmp_index]; return prev_count + curr_count; } };