LeetCode 493 Reverse Pairs / 315 Count of Smaller Numbers After Self

Similarity

  • Break down the array and solve for the subproblems

Three Implementation

  • Merge sort(guarantee O(nlogn))
  • BST(worst case O(n^2). Consider balanced-tree for insertion)
  • BIT(O(nlogn))

315 Count of Smaller Numbers After Self

You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i] is the number of smaller elements to the right of nums[i].

Example:
Input: [5,2,6,1]
Output: [2,1,1,0]
Explanation:
To the right of 5 there are 2 smaller elements (2 and 1).
To the right of 2 there is only 1 smaller element (1).
To the right of 6 there is 1 smaller element (1).
To the right of 1 there is 0 smaller element.

BST Solution

  • Node属性有:val表示Node的值,sum表示它左子树上总共的number,dup表示这个Node相同值的总共个数。
  • 根据给的数组从后往前建树,对每个插入的数,将插入的path上所有turn right的Node的sum和dup相加得到新Node的smaller numbers after self的个数,即把新插入的点后面的所有比它小的Node中,比Node小的数的个数和Node自身的dup个数相加。
public class Solution {
    class Node {
        Node left, right;
        int val, sum, dup = 1;
        public Node(int v, int s) {
            val = v;
            sum = s;
        }
    }
    public List countSmaller(int[] nums) {
        Integer[] ans = new Integer[nums.length];
        Node root = null;
        for (int i = nums.length - 1; i >= 0; i--) {
            root = insert(nums[i], root, ans, i, 0);
        }
        return Arrays.asList(ans);
    }
    private Node insert(int num, Node node, Integer[] ans, int i, int preSum) {
        if (node == null) {
            node = new Node(num, 0);
            ans[i] = preSum;
        } else if (node.val == num) {
            node.dup++;
            ans[i] = preSum + node.sum;
        } else if (node.val > num) {
            node.sum++;
            node.left = insert(num, node.left, ans, i, preSum);
        } else {
            node.right = insert(num, node.right, ans, i, preSum + node.dup + node.sum);
        }
        return node;
    }
}

MergeSort Solution

  • MergeSort-based solution is a standard way to solve problems related to inverse numbers.
  • 把一个array对半分为left array和right array,有一个rightcount,当merge时加入一个右子数组的数,说明左子数组中的每个数都有一个比它小的数在右边,所以rightcount加一;当merge时加入一个左子数组的数,就加上当前的rightcount
public class Solution {
    public List countSmaller(int[] nums) {
        int[] count = new int[nums.length];
        int[] indexes = new int[nums.length];
        for (int i=0; i res = new ArrayList();
        for (int i=0; i

BIT Solution

  • Both update() and query() operation have O(n) time complexity.
  • Space complexity: O(n)
  • Tree length is determined by maximum value of nums. Use long instead of integer in case it overflows
  • Pre-process the input array to guarantee no negative element leading to an out of index exception
public class Solution {
    public List countSmaller(int[] nums) {
        List res = new ArrayList();
        if (nums == null || nums.length == 0) return res;
        int min = Integer.MAX_VALUE;
        int max = Integer.MIN_VALUE;
        for (int num : nums) {
            min = Math.min(min, num);
        }
        int[] nums2 = new int[nums.length];
        for (int i=0; i=0; i--) {
            res.add(0, query(nums2[i] - 1, tree));
            update(nums2[i], tree);
        }
        return res;
    }
    private int query(int i, int[] tree) {
        int num = 0;
        while (i > 0) {
            num += tree[i];
            i -= i & (-i);
        }
        return num;
    }
    private void update(int i, int[] tree) {
        while (i < tree.length) {
            tree[i] ++;
            i += i & (-i);
        }
    }
}

493 Reverse Pairs

BST Solution

  • 建树时,如果插入的新的值等于一个节点的值,增加dup;如果小于这个节点的值,把这个节点的less增加一并对它的左子节点插入这个值
  • search时,要找小于target(target = (double) nums[i] / 2)的值,当找到节点的值等于target,直接加上less即小于该节点的节点个数;当找到的节点的值大于target,往左子树找;当找到的节点的值小于target,加上该节点的less并往右子树中找满足要求的节点
  • 对sorted array(worst case)会超时
class Solution {
    public int reversePairs(int[] nums) {
        Node root = null;
        int cnt = 0;
        for (int i=nums.length-1; i>=0; i--) {
            cnt = search(cnt, root, nums[i] / 2.0);
            root = buildTree(nums[i], root);
        }
        return cnt;
    }
    private Node buildTree(int val, Node node) {
        if (node == null) return new Node(val);
        if (node.val == val) {
            node.dup ++;
        }
        else if (node.val > val) {
            node.less ++;
            node.left = buildTree(val, node.left);
        }
        else {
            node.right = buildTree(val, node.right);
        }
        return node;
    }
    private int search(int cnt, Node node, double target) {
        if (node == null) return cnt;
        if (target < node.val) {
            return search(cnt, node.left, target);
        }
        else if (target == node.val) {
            return cnt + node.less;
        }
        else {
            return search(cnt + node.less + node.dup, node.right, target);
        }
    }
}
class Node {
    int val, less, dup;
    Node left, right;
    public Node(int _val) {
        val = _val;
        dup = 1;
    }
}

MergeSort Solution

  • 对每个右数组的数,如果它和左数组的nums[i]能够满足条件,那么它就能和左数组中第i+n(n>=0)元素满足条件。
  • 用/2.0防止overflow
class Solution {
    public int reversePairs(int[] nums) {
        return mergeSort(nums, 0, nums.length - 1);
    }
    private int mergeSort(int[] nums, int start, int end) {
        if (start >= end) return 0;
        int mid = start + (end - start) / 2;
        int cnt = mergeSort(nums, start, mid) + mergeSort(nums, mid+1, end);
        for (int i=start, j=mid+1; i<=mid; i++) {
            while (j <= end && nums[i] / 2.0 > nums[j]) j ++;
            cnt += j - (mid + 1);
        }
        Arrays.sort(nums, start, end + 1);
        return cnt;
    }
}

BIT Solution

  • 把int array转换成long array防止overflow
  • 两个operation:从左到右search(2 * num + 1)在sorted array中的位置,并query()比它大的数;update() index with the accumulated count
  • Arrays.binarySearch : If the array contains multiple elements with the specified value, there is no guarantee which one will be found.
class Solution {
    public int reversePairs(int[] nums) {
        int n = nums.length;
        
        // why long? 2 * nums[i] could overflow
        // why this array? need its indexes to build bit
        long[] nums2 = new long[n];
        for (int i = 0; i < n; i++) {
            nums2[i] = (long)nums[i];
        }
        Arrays.sort(nums2);
        
        int[] bit = new int[n + 1];
        
        int count = 0;
        
        for (int i = 0; i < n; i++) {
            int curr = nums[i];
            
            int idx1 = Arrays.binarySearch(nums2, 2l * curr + 1);
            count += query(bit, (idx1 < 0 ? -(idx1 + 1) : idx1) + 1);

            int idx2 = Arrays.binarySearch(nums2, curr);
            insert(bit, (idx2 < 0 ? -(idx2 + 1) : idx2) + 1, 1);
        }
        
        return count;    
    }
    
    private int query(int[] bit, int x) {
        int res = 0;
        
        for (int i = x; i < bit.length; i += i & -i) {
            res += bit[i];
        }
        
        return res;
    }
    
    private void insert(int[] bit, int x, int val) {
        for (int i = x; i > 0; i -= i & -i) {
            bit[i] += val;
        }
    }
}

Reference

General principles behind problems similar to "Reverse Pairs"

你可能感兴趣的:(LeetCode 493 Reverse Pairs / 315 Count of Smaller Numbers After Self)