Sliding Subarray Beauty
Sliding Subarray Beauty
š§© Problem Statement
Given an integer array nums containing n integers, find the beauty of each subarray of size k.
The beauty of a subarray is the x-th smallest integer in the subarray if it is negative, or 0 if there are fewer than x negative integers.
Return an integer array containing n - k + 1 integers, which denote the beauty of the subarrays.
š¹ Example 1:
Input:
nums = [1, -1, -3, -2, 3], k = 3, x = 2
Output:
[-1, -2, -2]
Explanation:
[1, -1, -3]: Negatives are {-3, -1}. 2nd smallest is -1.[-1, -3, -2]: Negatives are {-3, -2, -1}. 2nd smallest is -2.[-3, -2, 3]: Negatives are {-3, -2}. 2nd smallest is -2.
š¹ Example 2:
Input:
nums = [-1, -2, -3], k = 2, x = 1
Output:
[-2, -3]
š Approaches
1. Sliding Window with Tree Map / Sorted List
Use a data structure that keeps elements sorted and supports adding/removing elements.
std::multisetin C++ orSortedListin Python.- Finding the x-th element takes $O(k)$ or $O(\log k)$ depending on augmentation.
- Total time: $O(n \log k)$ or $O(nk)$.
2. Frequency Array (Counting Sort Logic)
The problem constraints usually specify a small range for nums[i] (e.g., -50 to 50).
- Since the range is small ($R \approx 100$), we can use a frequency array
freqof sizeR. - We only care about negative numbers
[-50, -1]. - Maintain
freqof numbers in the current window. - To find the x-th smallest number:
- Iterate from the smallest possible number (-50) upwards.
- Subtract the count of the current number from
x. - If
x <= 0, we found the x-th smallest. - This query takes $O(R)$ time (constant-ish).
- Sliding takes $O(1)$ time to update
freq. - Total time: $O(n \cdot R)$. This is very fast when $R$ is small.
⨠Intuition
Since we only care about the relative order of small integers, we don't need sorting. We just need to know "how many -50s, how many -49s..." via buckets.
š„ Algorithm Steps
- Create a frequency array
countfor range[-50, 50](offset by +50 to make indices positive). - Populate
countfor the firstkelements. - Function
findXth():
countthrough range-50to-1.- Accumulate counts. Stop when sum $\ge x$.
- Return that number. Return 0 otherwise.
- Iterate
ifromkton.
- Update
result[i-k]usingfindXth(). - Remove
nums[i-k]fromcount. - Add
nums[i]tocount.
- Compute last window result.
ā³ Time & Space Complexity
- Time Complexity: $O(n \cdot 50)$.
- Space Complexity: $O(1)$ (frequency array size fixed).
š Code Implementations
C++
#include <vector>
using namespace std;
class Solution {
public:
vector<int> getSubarrayBeauty(vector<int>& nums, int k, int x) {
int count[101] = {0}; // Offset by 50. Index 0 is -50, 50 is 0.
int n = nums.size();
vector<int> result;
for (int i = 0; i < k; i++) {
count[nums[i] + 50]++;
}
result.push_back(findXth(count, x));
for (int i = k; i < n; i++) {
count[nums[i] + 50]++;
count[nums[i - k] + 50]--;
result.push_back(findXth(count, x));
}
return result;
}
private:
int findXth(int count[], int x) {
int currentCount = 0;
// Check only negative numbers: -50 to -1
// Indices 0 to 49 corresponds to -50 to -1
for (int i = 0; i < 50; i++) {
currentCount += count[i];
if (currentCount >= x) {
return i - 50;
}
}
return 0;
}
};
Python
class Solution:
def getSubarrayBeauty(self, nums: List[int], k: int, x: int) -> List[int]:
count = [0] * 101 # -50 to 50
res = []
def find_xth():
current_count = 0
# Iterate -50 to -1
for val in range(-50, 0):
current_count += count[val + 50]
if current_count >= x:
return val
return 0
# Init first window
for i in range(k):
count[nums[i] + 50] += 1
res.append(find_xth())
# Slide
for i in range(k, len(nums)):
count[nums[i] + 50] += 1
count[nums[i - k] + 50] -= 1
res.append(find_xth())
return res
Java
class Solution {
public int[] getSubarrayBeauty(int[] nums, int k, int x) {
int[] count = new int[101]; // -50 to 50
int n = nums.length;
int[] result = new int[n - k + 1];
for (int i = 0; i < k; i++) {
count[nums[i] + 50]++;
}
result[0] = findXth(count, x);
for (int i = k; i < n; i++) {
count[nums[i] + 50]++;
count[nums[i - k] + 50]--;
result[i - k + 1] = findXth(count, x);
}
return result;
}
private int findXth(int[] count, int x) {
int currentCount = 0;
// Check -50 to -1 (indices 0 to 49)
for (int i = 0; i < 50; i++) {
currentCount += count[i];
if (currentCount >= x) {
return i - 50;
}
}
return 0;
}
}
š Real-World Analogy
Grading on a Curve (Bottom Scores):
A teacher looks at the last k exam papers graded.
They want to know the "2nd worst score" (x=2) in that batch to see if students are struggling, but they only care if the score is failing (negative).
Because scores are integers 0-100 (or shifted range), they just keep tally counts of each score.
šÆ Summary
ā
Frequency Array: Exploits small range of values.
ā
Fixed Window: Standard add/remove pattern.
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<int> getSubarrayBeauty(vector<int> &nums, int k, int x) {
int count[101] = {0}; // Offset by 50. Index 0 is -50, 50 is 0.
int n = nums.size();
vector<int> result;
for (int i = 0; i < k; i++) {
count[nums[i] + 50]++;
}
result.push_back(findXth(count, x));
for (int i = k; i < n; i++) {
count[nums[i] + 50]++;
count[nums[i - k] + 50]--;
result.push_back(findXth(count, x));
}
return result;
}
private:
int findXth(int count[], int x) {
int currentCount = 0;
// Check only negative numbers: -50 to -1
// Indices 0 to 49 corresponds to -50 to -1
for (int i = 0; i < 50; i++) {
currentCount += count[i];
if (currentCount >= x) {
return i - 50;
}
}
return 0;
}
};
int main() {
Solution sol;
vector<int> nums1 = {1, -1, -3, -2, 3};
int k1 = 3, x1 = 2;
vector<int> res1 = sol.getSubarrayBeauty(nums1, k1, x1);
cout << "Beauty 1: ";
for (int b : res1)
cout << b << " "; // Expected: -1 -2 -2
cout << endl;
vector<int> nums2 = {-1, -2, -3};
int k2 = 2, x2 = 1;
vector<int> res2 = sol.getSubarrayBeauty(nums2, k2, x2);
cout << "Beauty 2: ";
for (int b : res2)
cout << b << " "; // Expected: -2 -3
cout << endl;
return 0;
}