[LeetCode] Reverse Pairs | 歸並排序找逆序對


https://leetcode.com/problems/reverse-pairs/#/description

和315, 327是一類題。

分治法,合並的過程就是歸並排序,在歸並的過程中,對右半邊,統計滿足nums[j] < nums[i] / 2的元素的個數即可。

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        if (nums.empty()) return 0;
        return count(nums, 0, nums.size() - 1);
    }
private:
    int count(vector<int>& nums, int start, int end) {
        if (start >= end) return 0;
        int mid = start + (end - start) / 2;
        int left = count(nums, start, mid);
        int right = count(nums, mid+1, end);
        int cross = merge(nums, start, mid ,end);
        return ( left + right + cross );
    }
    
    int merge(vector<int>& nums, int start, int mid, int end) {
        int cnt = 0, p = start, q = mid + 1, r = 0;
        vector<int> helper(end-start+1);
        // 統計
        vector<int>::iterator up, low = nums.begin() + mid+1;
        for (int i = start; i <= mid; ++i) {
            up = std::upper_bound(nums.begin() + mid+1, nums.begin() + end+1, ceil(nums[i] / 2.0)-1); // 不包含nums[i]/2
            cnt += (up - low);
        }
        // 歸並
        while (p <= mid && q <= end) {
            if (nums[p] < nums[q]) helper[r++] = nums[p++];
            else helper[r++] = nums[q++];
        }
        while (p <= mid) helper[r++] = nums[p++];
        while (q <= end) helper[r++] = nums[q++];
        copy(helper.begin(), helper.end(), nums.begin() + start);
        
        return cnt;
    }
};

leetcode 327,是對前綴和數組的操作(涉及到區間統計,思維慣性是往前綴和或者區間DP方向走),若設S(i)表示nums[0..i]之和,S(i,j)表示nums[i...j]之和,計數條件就是lower <= S(i,j) <= upper,即lower <= S(j) - S(i-1) <= upper,即S(i-1)+lower <= S(j) <= S(i-1) + upper;逆序對以及今天的問題,都是對原數組操作,只是條件變為了nums(i) > 2*nums(j),或nums(j) < nums(i) / 2,按不等式條件進行統計即可,其他形式的統計亦然。

注意,雖然字面意思是歸並排序,但是因果關系並不是“歸並排序有統計的功能”,而是為了加速計數過程,最好能創造一些條件,比如“數組能有序,而且不改變結果”。如果說解決這個問題的出發點是分治,只不過恰好統計的過程需要做排序,而這樣的實現碰巧就是歸並排序~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM