「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」
315. 计算右侧小于当前元素的个数
给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例 1:
输入:nums = [5,2,6,1]
输出:[2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素
示例 2:
输入: nums = [-1]
输出: [0]
示例 3:
入: nums = [-1,-1]
输出: [0,0]
提示:
1 <= nums.length <= 105-104 <= nums[i] <= 104
暴力求解
思路
直接双循环,大佬们肯定都知道,我们就略过
归并排序
思路 由题可得我们这道题目要求数组中每一位元素的右侧所有元素中,比当前元素值小的元素的个数,正如示例中所示
我们会发现先这个题目跟剑指 Offer 51. 数组中的逆序对非常相似
逆序对:求所有逆序对的个数 当前:求右侧小于当前元素的个数
本质上是同一个道理,只是本题中需要区分出来每个值构成的逆序对的数量,而不是所有逆序对的总数
这里我们采用归并排序的方式。
为什么用归并排序? 因为数组一旦有序,那么就不需要逐一遍历了,而是可以找到一个临界点,直接计算求解
假设当前有两个有序数组left[1,3,5] rightp[2,4,6]
因为1小于2,所以1右侧小于它的值的数量直接为0
因为3大于1小于4,所以3右侧所有小于它的值的数量直接等于1(4的下标1)
因为5大于4小于6,所以4右侧所有小于它的值的数量直接等于2(6的下标2)
这样就大大降低了时间复杂度(相比暴力求解)
实现方式
我们采用归并排序的方式,每次会将数组从中间均分,分别得到两个有序的数组
我们声明i指针用来遍历sortLeft,用p指向sortRight的首位
遍历sortLeft的值,没一个值与右侧的sortRight[p]进行比较,如果右侧的值比较小则p++
p的下标值就是sortRight中小于left[i]的数量,所以left[i]右侧小于它的值+=p
我们怎么记录原数组中每一个值右侧的数量呢?排序打乱数组顺序怎么记得原来的顺序呢
- 这里我们直接把每个值变成一个对象,{val:值,res:0}
- 也可以用一个数组来记录原来数组中的位置,与数组一起进行排序 这样在排序的时候我们就可以吧每个值的结果+=在他的res中
最后从数组中取出res即可
var countSmaller = function (nums) {
var i = 0
while (i < nums.length) {
nums[i] = {val:nums[i],res:0}
i++
}
function computedNum(nums) {
if (nums.length < 2) return nums
var len = nums.length
var mid = len >> 1
var left = nums.slice(0, mid)
var right = nums.slice(mid)
var sortLeft = computedNum(left)
var sortRight = computedNum(right)
// 开始统计right中的小于left的值
var i = 0
var p = 0
while (i < left.length) {
var item = sortLeft[i]
while (sortRight[p] && item.val > sortRight[p].val && p < sortRight.length) p++
item.res += p
i++
}
// 合并数组
var arr = Array(nums.length)
var index = 0;
var p = q = 0
while (index < nums.length) {
if (p === sortLeft.length) {
arr[index++] = sortRight[q++]
} else if (q === sortRight.length) {
arr[index++] = sortLeft[p++]
} else if (sortLeft[p].val < sortRight[q].val) {
arr[index++] = sortLeft[p++]
} else {
arr[index++] = sortRight[q++]
}
}
return arr
}
computedNum(nums)
var j = 0
while (j < nums.length) {
nums[j] = nums[j].res
j++
}
return nums
};