给你一个长度为 n
的整数数组 nums
,请你求出每个长度为 k
的子数组的 美丽值 。
一个子数组的 美丽值 定义为:如果子数组中第 x
小整数 是 负数 ,那么美丽值为第 x
小的数,否则美丽值为0
。
请你返回一个包含 _ _n - k + 1
个整数的数组, 依次 表示数组中从第一个下标开始,每个长度为 k
的子数组的 ** 美丽值** 。
示例 1:
**输入:** nums = [1,-1,-3,-2,3], k = 3, x = 2
**输出:** [-1,-2,-2]
**解释:** 总共有 3 个 k = 3 的子数组。
第一个子数组是 [1, -1, -3] ,第二小的数是负数 -1 。
第二个子数组是 [-1, -3, -2] ,第二小的数是负数 -2 。
第三个子数组是 [-3, -2, 3] ,第二小的数是负数 -2 。
示例 2:
**输入:** nums = [-1,-2,-3,-4,-5], k = 2, x = 2
**输出:** [-1,-2,-3,-4]
**解释:** 总共有 4 个 k = 2 的子数组。
[-1, -2] 中第二小的数是负数 -1 。
[-2, -3] 中第二小的数是负数 -2 。
[-3, -4] 中第二小的数是负数 -3 。
[-4, -5] 中第二小的数是负数 -4 。
示例 3:
**输入:** nums = [-3,1,2,-3,0,-3], k = 2, x = 1
**输出:** [-3,0,-3,-3,-3]
**解释:** 总共有 5 个 k = 2 的子数组。
[-3, 1] 中最小的数是负数 -3 。
[1, 2] 中最小的数不是负数,所以美丽值为 0 。
[2, -3] 中最小的数是负数 -3 。
[-3, 0] 中最小的数是负数 -3 。
[0, -3] 中最小的数是负数 -3 。
提示:
n == nums.length
1 <= n <= 105
1 <= k <= n
1 <= x <= k
-50 <= nums[i] <= 50
本题视频讲解 见【周赛 342】 第三题。
思路 滑动窗口。由于值域很小,所以借鉴计数排序 ,用一个 cnt 数组维护窗口内每个数的出现次数。然后遍历 cnt 去求第 x 小的数。
什么是第 x 小的数?
设它是 num,那么 <\textit{num 的数有 <x 个,\le\textit{num 的数有 \ge x 个,就说明 num 是第 x 小的数。
[sol1-Python3] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution : def getSubarrayBeauty (self, nums: List [int ], k: int , x: int ) -> List [int ]: cnt = [0 ] * 101 for num in nums[:k - 1 ]: cnt[num] += 1 ans = [0 ] * (len (nums) - k + 1 ) for i, (in_, out) in enumerate (zip (nums[k - 1 :], nums)): cnt[in_] += 1 left = x for j in range (-50 , 0 ): left -= cnt[j] if left <= 0 : ans[i] = j break cnt[out] -= 1 return ans
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public int [] getSubarrayBeauty(int [] nums, int k, int x) { final int BIAS = 50 ; var cnt = new int [BIAS * 2 + 1 ]; int n = nums.length; for (int i = 0 ; i < k - 1 ; ++i) ++cnt[nums[i] + BIAS]; var ans = new int [n - k + 1 ]; for (int i = k - 1 ; i < n; ++i) { ++cnt[nums[i] + BIAS]; int left = x; for (int j = 0 ; j < BIAS; ++j) { left -= cnt[j]; if (left <= 0 ) { ans[i - k + 1 ] = j - BIAS; break ; } } --cnt[nums[i - k + 1 ] + BIAS]; } return ans; } }
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : vector<int > getSubarrayBeauty (vector<int > &nums, int k, int x) { const int BIAS = 50 ; int cnt[BIAS * 2 + 1 ]{}, n = nums.size (); for (int i = 0 ; i < k - 1 ; ++i) ++cnt[nums[i] + BIAS]; vector<int > ans (n - k + 1 ) ; for (int i = k - 1 ; i < n; ++i) { ++cnt[nums[i] + BIAS]; int left = x; for (int j = 0 ; j < BIAS; ++j) { left -= cnt[j]; if (left <= 0 ) { ans[i - k + 1 ] = j - BIAS; break ; } } --cnt[nums[i - k + 1 ] + BIAS]; } return ans; } };
[sol1-Go] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func getSubarrayBeauty (nums []int , k, x int ) []int { const bias = 50 cnt := [bias*2 + 1 ]int {} for _, num := range nums[:k-1 ] { cnt[num+bias]++ } ans := make ([]int , len (nums)-k+1 ) for i, num := range nums[k-1 :] { cnt[num+bias]++ left := x for j, c := range cnt[:bias] { left -= c if left <= 0 { ans[i] = j - bias break } } cnt[nums[i]+bias]-- } return ans }
复杂度分析
时间复杂度:\mathcal{O}(nU),其中 n 为 nums 的长度,U=50。
空间复杂度:\mathcal{O}(U)。