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<Integer> 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<Integer> countSmaller(int[] nums) {
        int[] count = new int[nums.length];
        int[] indexes = new int[nums.length];
        for (int i=0; i<indexes.length; i++) {
            indexes[i] = i;
        }
        mergeSort(nums, count, indexes, 0, nums.length - 1);
        List<Integer> res = new ArrayList<Integer>();
        for (int i=0; i<nums.length; i++) {
            res.add(count[i]);
        }
        return res;
    }
    public void mergeSort(int[] nums, int[] count, int[] indexes, int start, int end) {
        if (end <= start) return;
        int mid = (start + end) / 2;
        mergeSort(nums, count, indexes, start, mid);
        mergeSort(nums, count, indexes, mid + 1, end);
        merge(nums, count, indexes, start, end);
    }
    public void merge(int[] nums, int[] count, int[] indexes, int start, int end) {
        int mid = (start + end) / 2;
        int left_index = start;
        int right_index = mid+1;
        int rightcount = 0;     
        int[] new_indexes = new int[end - start + 1];

        int sort_index = 0;
        while(left_index <= mid && right_index <= end){
            if(nums[indexes[right_index]] < nums[indexes[left_index]]){
                new_indexes[sort_index] = indexes[right_index];
                rightcount++;
                right_index++;
            }else{
                new_indexes[sort_index] = indexes[left_index];
                count[indexes[left_index]] += rightcount;
                left_index++;
            }
            sort_index++;
        }
        while(left_index <= mid){
            new_indexes[sort_index] = indexes[left_index];
            count[indexes[left_index]] += rightcount;
            left_index++;
            sort_index++;
        }
        while(right_index <= end){
            new_indexes[sort_index++] = indexes[right_index++];
        }
        for(int i = start; i <= end; i++){
            indexes[i] = new_indexes[i - start];
        }
    }
}

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<Integer> countSmaller(int[] nums) {
        List<Integer> res = new ArrayList<Integer>();
        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<nums.length; i++) {
            nums2[i] = nums[i] - min + 1;
            max = Math.max(max, nums2[i]);
        }
        int[] tree = new int[max + 1];
        for (int i=nums2.length-1; 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"

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容