一、題目描述
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;
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
方法二:二分
可以想象一下有 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);
}
複雜度分析
- 時間複雜度:,
- 空間複雜度:,