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:
Given nums = [5, 2, 6, 1]
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.
Return the array [2, 1, 1, 0]
.
这道题给定我们一个数组,让我们计算每个数字右边所有小于这个数字的个数,目测我们不能用brute force,OJ肯定不答应,那么我们为了提高运算效率,首先可以使用用二分搜索法,思路是将给定数组从最后一个开始,用二分法插入到一个新的数组,这样新数组就是有序的,那么此时该数字在新数组中的坐标就是原数组中其右边所有较小数字的个数,参见代码如下:
// Binary Search
class Solution {
public:
vector<int> countSmaller(vector<int>& nums) {
vector<int> t, res(nums.size());
for (int i = nums.size() - 1; i >= 0; --i) {
int left = 0, right = t.size();
while (left < right) {
int mid = left + (right - left) / 2;
if (t[mid] >= nums[i]) right = mid;
else left = mid + 1;
}
res[i] = right;
t.insert(t.begin() + right, nums[i]);
}
return res;
}
};
这道题,实在是秒。
起初我也是想,在右边一堆“无序”数组中,找比当前小的,这里无序,所以无法用二分。
1 肯定有个过程,那就是找离他最近的那个点,那么就可以采用二分搜索法。
2 没想到的是,开辟一个新数组,且往里面插值,且是已排序的。这样下标就直接反应了个数。
1 最终要控制一个集中点,所以左右两边步长只能控制一个-1,不能一个mid+1,一个mid-1,这个可能最后相差-2.
2 在新数组中插入相同的元素时(之前已经有一个),应该往左边插,如果往右边插,则会多一个。
即 找到新数组中的位置,最左边的那个。