zoukankan      html  css  js  c++  java
  • [LeetCode 493] Reverse Pairs

    Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].

    You need to return the number of important reverse pairs in the given array.

    Example1:

    Input: [1,3,2,3,1]
    Output: 2
    

     

    Example2:

    Input: [2,4,3,5,1]
    Output: 3
    

     

    Note:

    1. The length of the given array will not exceed 50,000.
    2. All the numbers in the input array are in the range of 32-bit integer.

    Solution 1. Binary Indexed Tree with binary search or coordinate compression, O(N * logN)

    The keys of a binary indexed tree are all the possible number values. So the high level idea of using a BIT here is that we process each nums[i] from left to right, check the count of > 2 * nums[i] and update ans, then update BIT with nums[i] appearing one more time. 

    Memory Limitation: The input length is up to 5 * 10^4, but there is no constraint on each input array number. It can be as big as Integer.MAX_VALUE or as small as Integer.MIN_VALUE. But we know there can be at most 5 * 10^4 unique numbers and will use this to get around the memory limitation here. 

    The first approach is to use binary search: get a copy of nums, sort it, and create a BIT of size nums.length + 1 as there will be at most nums.length unique numbers. The relative order of nums[i] is matched to BIT's key in the following manner:

    1. nums[i] -> binary search to find the leftmost nums[i]' index J and use J + 1 to update; Guanranteed to find a match; 

    2. nums[i] * 2 + 1 -> binary search to find the leftmost index K such that nums[K] >= nums[i] * 2 + 1;  May not exist;

    class BinaryIndexedTree {
        int[] ft;
        BinaryIndexedTree(int n) {
            ft = new int[n];
        }
        int rangeSum(int r) {
            int sum = 0;
            for(; r > 0; r -= (r & (-r))) {
                sum += ft[r];
            }
            return sum;
        }
        void update(int k, int v) {
            for(; k < ft.length; k += (k & (-k))) {
                ft[k] += v;
            }
        }
    }
    class Solution {
        public int reversePairs(int[] nums) {
            int n = nums.length, ans = 0;
            int[] a = Arrays.copyOf(nums, nums.length);
            Arrays.sort(a);
            BinaryIndexedTree bit = new BinaryIndexedTree(n + 1);
            for(int i = 0; i < n; i++) {
                int idx = index(a, 2L * nums[i] + 1);
                if(idx <= n) {
                    ans += bit.rangeSum(n) - bit.rangeSum(idx);
                }
                bit.update(index(a, nums[i]) + 1, 1);
            }
            return ans;
        }
        //find the leftmost index i such that a[i] >= target
        private int index(int[] a, long target) {
            int l = 0, r = a.length - 1;
            while(l < r - 1) {
                int mid = l + (r - l) / 2;
                if(a[mid] >= target) {
                    r = mid;
                }
                else {
                    l = mid + 1;
                }
            }
            if(a[l] >= target) {
                return l;
            }
            else if(a[r] >= target) {
                return r;
            }
            return a.length + 1;
        }
    }

    The second approach is to use coordinate compression:  Combine all nums[i] * 2 along with nums[i] and sort the combined values. For each unqiue value, assign an index to it. The rest logic is pretty much the same with the binary search approach.

    class BinaryIndexedTree {
        int[] ft;
        BinaryIndexedTree(int n) {
            ft = new int[n];
        }
        int rangeSum(int r) {
            int sum = 0;
            for(; r > 0; r -= (r & (-r))) {
                sum += ft[r];
            }
            return sum;
        }
        void update(int k, int v) {
            for(; k < ft.length; k += (k & (-k))) {
                ft[k] += v;
            }
        }
    }
    class Solution {
        public int reversePairs(int[] nums) {
            Map<Long, Integer> compressMap = coordCompress(nums);
            int n = compressMap.size(), ans = 0;
            BinaryIndexedTree bit = new BinaryIndexedTree(n + 1);
            for(int i = 0; i < nums.length; i++) {
                ans += bit.rangeSum(n) - bit.rangeSum(compressMap.get(2L * nums[i]));
                bit.update(compressMap.get(1L * nums[i]), 1);
            }
            return ans;
        }
        private Map<Long, Integer> coordCompress(int[] a) {
            Map<Long, Integer> map = new HashMap<>();
            long[] b = new long[a.length * 2];
            int j = 0;
            for(int i = 0; i < a.length; i++) {
                b[j] = a[i];
                j++;
                b[j] = 2L * a[i];
                j++;
            }
            Arrays.sort(b);
            int idx = 1;
            for(long v : b) {
                if(!map.containsKey(v)) {
                    map.put(v, idx);
                    idx++;
                }
            }
            return map;
        }
    }

     Solution 2. Divide and Conquer, Merge Sort based approach, O(N * logN)

    If we divide nums into two subarrays left and right of equal length, then the final answer is the answer of left and right + the count where the 1st element is from left and the 2nd element is from right.  If after solving the subproblems on left and right, these two subarrays are also in sorted order, then we can count the cross pair in linear time by using two pointers. This can be embedded into merge sort.

    class Solution {
        public int reversePairs(int[] nums) {
            return mergeSort(nums, new int[nums.length], 0, nums.length - 1);
        }
        private int mergeSort(int[] a, int[] aux, int l, int r) {
            if(l >= r) return 0;
            int mid = l + (r - l) / 2;
            int cnt = mergeSort(a, aux, l, mid) + mergeSort(a, aux, mid + 1, r);
            for(int i = l; i <= r; i++) {
                aux[i] = a[i];
            }
            int k1 = l, k2 = mid + 1;
            while(k1 <= mid && k2 <= r) {
                if(aux[k1] > 2L * aux[k2]) {
                    cnt += (mid - k1 + 1);
                    k2++;
                }
                else {
                    k1++;
                }
            }
            k1 = l;
            k2 = mid + 1;
            for(int i = l; i <= r; i++) {
                if(k1 <= mid && k2 <= r) {
                    if(aux[k1] <= aux[k2]) {
                        a[i] = aux[k1];
                        k1++;
                    }
                    else {
                        a[i] = aux[k2];
                        k2++;
                    }
                }
                else if(k1 <= mid) {
                    a[i] = aux[k1];
                    k1++;
                }
                else {
                    a[i] = aux[k2];
                    k2++;
                }
            }
            return cnt;
        }
    }

    Related Problems

    [LeetCode 315] Count of Smaller Numbers After Self

  • 相关阅读:
    03 http请求协议与响应协议
    02 web应用程序
    Django web框架目录
    01 http协议
    Django框架
    Bootstrap栅格系统
    bootstrap介绍和引入
    Python中日志logging模块
    Python 装饰器实现单列模式
    Python 如何理解可更改元组中的可变序列
  • 原文地址:https://www.cnblogs.com/lz87/p/11846144.html
Copyright © 2011-2022 走看看