【贪心】A_012 计算右侧小于当前元素的个数(暴力 | 二分搜索)

一、题目描述

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].

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.

二、题解

方法一:暴力(超时)

额…,

public List<Integer> countSmaller(int[] nums) {
    List<Integer> list = new LinkedList<>();
    for (int i = 0; i < nums.length; i++) {
        int count = 0;
        for (int j = i+1; j < nums.length; j++) {
            if (nums[j] < nums[i])
                count++;
        }
        list.add(count);
    }
    return list;
}

复杂度分析

  • 时间复杂度:O(n2)O(n^2)
  • 空间复杂度:O(n)O(n)

方法二:二分

可以想象一下有 5 个人的按升高升序排列队伍进行报数,当报到 3 的时候,右边很容易得到右 2 个人。如果队伍无序则很麻烦。需要一个一个地向后数。

我们选择从右往左查询,每次查询到 1 个数时,我们将其插入到 sorted_list 中,怎么插入呢?我们选择的位置是在 sorted_list 中找到一个小于 nums[i] 的最大元素,我们将 nums[i] 插入到该元素的后面。

这样就能根据插入的位置判断有多少个元素比自己小了,又因为是从右往左枚举的,所以插入的位置代表了右边有多少个元素比自己小。

[1,3,6,1,2,3]

loop 3,  output: [3] -> 3 左边有 0 个数,插在 0 位置
loop 2,  output: [2,3] -> 2 左边有 0 个数,插在 0 位置
loop 1,  output: [1,2,3] -> 1 左边有 0 个数,插在 0 位置
loop 6,  output: [1,2,3,6] -> 6 左边有 3 个数,插在 3 位置
loop 3', output: [1,2,3',3,6] -> 3' 左边有 2 个数,插在 2 位置
loop 1', output: [1',1,2,3',3,6] -> 1' 左边有 0 个数,插在 0 位置
public List<Integer> countSmaller(int[] nums) {
    List<Integer> list = new ArrayList<>();
    Integer[] res = new Integer[nums.length];

    for (int i = nums.length-1; i >= 0; i--) {
        int l = 0, r = list.size();
        while (l < r) {
            int mid = (l + r) >>> 1;
            if (nums[i] > list.get(mid)) {
                l = mid + 1;
            } else {
                r = mid;
            }
        }
        res[i] = l;
        list.add(l, nums[i]);
    }
    return Arrays.asList(res);
}

复杂度分析

  • 时间复杂度:O(nlgn)O(nlgn)
  • 空间复杂度:O(n)O(n)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章