3255. Find the Power of K-Size Subarrays II
Problem Description
You are given an array of integers nums
of length n
and a positive integer k
.
The problem asks you to find the "power" of all subarrays of size k
in the given array. The power of an array is defined with specific rules:
- If all elements in the subarray are consecutive and sorted in ascending order, the power equals the maximum element (which would be the last element in this case)
- Otherwise, the power is -1
For an array to have consecutive and sorted elements in ascending order, each element must be exactly 1 greater than the previous element. For example, [3, 4, 5]
is consecutive and sorted, but [3, 5, 6]
is not consecutive (missing 4), and [5, 4, 3]
is not sorted in ascending order.
You need to examine every subarray of size k
in the array nums
. Starting from index 0, check the subarray nums[0..k-1]
, then nums[1..k]
, then nums[2..k+1]
, and so on, until you reach the last possible subarray nums[n-k..n-1]
.
The output should be an array results
of size n - k + 1
, where results[i]
contains the power of the subarray starting at index i
and having length k
.
For example, if nums = [1, 2, 3, 4, 3, 2, 5]
and k = 3
:
- Subarray
[1, 2, 3]
: consecutive and sorted → power = 3 - Subarray
[2, 3, 4]
: consecutive and sorted → power = 4 - Subarray
[3, 4, 3]
: not consecutive/sorted → power = -1 - Subarray
[4, 3, 2]
: not sorted in ascending order → power = -1 - Subarray
[3, 2, 5]
: not consecutive → power = -1
The result would be [3, 4, -1, -1, -1]
.
Intuition
The key insight is that we don't need to check each subarray of size k
independently. Instead, we can precompute information about consecutive increasing sequences throughout the entire array.
Think about what makes a subarray valid: every element must be exactly 1 greater than the previous element. If we know how many consecutive increasing elements end at each position, we can quickly determine if a subarray of size k
is valid.
Consider this observation: if we're at position i
and we know that there are at least k
consecutive increasing elements ending at position i
, then the subarray ending at position i
with length k
must be valid. For example, if at index 5 we have 4 consecutive increasing elements ending there (like [3, 4, 5, 6]
), then any subarray of size 3 or less ending at index 5 would be valid.
This leads us to create an auxiliary array f
where f[i]
represents the length of the consecutive increasing sequence ending at index i
. We can build this array in a single pass:
- Start with
f[0] = 1
(every element forms a sequence of length 1 by itself) - For each subsequent position
i
, check ifnums[i] = nums[i-1] + 1
- If yes, then
f[i] = f[i-1] + 1
(extending the previous sequence) - If no, then
f[i] = 1
(starting a new sequence)
- If yes, then
Once we have the f
array, checking if a subarray of size k
ending at position i
is valid becomes trivial: just check if f[i] >= k
. If it is, the power is nums[i]
(the maximum element in that consecutive sequence); otherwise, it's -1.
This approach transforms a problem that seems to require checking each subarray individually (which would involve nested loops) into a problem solvable with two simple linear passes through the array.
Learn more about Sliding Window patterns.
Solution Approach
The solution implements the precomputation strategy using dynamic programming principles:
Step 1: Initialize the consecutive sequence length array
Create an array f
of size n
where each element is initialized to 1. This represents that every element forms at least a sequence of length 1 by itself.
f = [1] * n
Step 2: Build the consecutive sequence information
Traverse the array from index 1 to n-1
. For each position i
, check if the current element forms a consecutive sequence with the previous element:
for i in range(1, n):
if nums[i] == nums[i - 1] + 1:
f[i] = f[i - 1] + 1
- If
nums[i] = nums[i-1] + 1
, it means the current element continues the consecutive increasing sequence from the previous position, so we setf[i] = f[i-1] + 1
- Otherwise,
f[i]
remains 1, indicating a new sequence starts at this position
Step 3: Generate the results
For each possible subarray of size k
, we check the ending position to determine the power:
return [nums[i] if f[i] >= k else -1 for i in range(k - 1, n)]
- We iterate from index
k-1
ton-1
(these are the ending positions of all possible subarrays of sizek
) - For each ending position
i
, iff[i] >= k
, it means there are at leastk
consecutive increasing elements ending at positioni
, making the subarray valid- The power is
nums[i]
(the maximum element in the consecutive sequence)
- The power is
- If
f[i] < k
, the subarray is not valid, so the power is -1
Time Complexity: O(n)
- We make two linear passes through the array
Space Complexity: O(n)
- We use an additional array f
of size n
to store the consecutive sequence lengths
This approach efficiently solves the problem by transforming it from checking each subarray individually to a simple lookup operation after preprocessing.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example with nums = [1, 2, 3, 1, 2]
and k = 3
.
Step 1: Build the consecutive sequence length array f
We initialize f = [1, 1, 1, 1, 1]
(every element starts as a sequence of length 1).
Now we traverse from index 1 to 4:
-
At index 1:
nums[1] = 2
andnums[0] = 1
. Since2 = 1 + 1
, we have consecutive elements.
Update:f[1] = f[0] + 1 = 1 + 1 = 2
Result:f = [1, 2, 1, 1, 1]
-
At index 2:
nums[2] = 3
andnums[1] = 2
. Since3 = 2 + 1
, consecutive!
Update:f[2] = f[1] + 1 = 2 + 1 = 3
Result:f = [1, 2, 3, 1, 1]
-
At index 3:
nums[3] = 1
andnums[2] = 3
. Since1 ≠ 3 + 1
, not consecutive.
No update needed (remains 1).
Result:f = [1, 2, 3, 1, 1]
-
At index 4:
nums[4] = 2
andnums[3] = 1
. Since2 = 1 + 1
, consecutive!
Update:f[4] = f[3] + 1 = 1 + 1 = 2
Final:f = [1, 2, 3, 1, 2]
Step 2: Generate results for each subarray of size k=3
We check subarrays ending at indices 2, 3, and 4:
-
Subarray [1, 2, 3] ends at index 2:
Check:f[2] = 3 >= k = 3
? Yes!
Power =nums[2] = 3
-
Subarray [2, 3, 1] ends at index 3:
Check:f[3] = 1 >= k = 3
? No.
Power =-1
-
Subarray [3, 1, 2] ends at index 4:
Check:f[4] = 2 >= k = 3
? No.
Power =-1
Final Result: [3, -1, -1]
The key insight: we only needed to check the value at the ending position of each subarray in our precomputed f
array, rather than examining all elements within each subarray. The f
array tells us exactly how many consecutive increasing elements end at each position, making the validation instant.
Solution Implementation
1class Solution:
2 def resultsArray(self, nums: List[int], k: int) -> List[int]:
3 n = len(nums)
4
5 # Track consecutive increasing sequence lengths ending at each index
6 consecutive_length = [1] * n
7
8 # Build the consecutive length array
9 # consecutive_length[i] represents the length of consecutive increasing sequence ending at index i
10 for i in range(1, n):
11 # Check if current element is exactly 1 more than previous element
12 if nums[i] == nums[i - 1] + 1:
13 # Extend the consecutive sequence
14 consecutive_length[i] = consecutive_length[i - 1] + 1
15
16 # Build result array for each window of size k
17 # For each window ending at index i (from k-1 to n-1):
18 # - If the consecutive sequence ending at i has length >= k,
19 # the window is consecutive and ascending, return the last element (nums[i])
20 # - Otherwise, return -1
21 result = []
22 for i in range(k - 1, n):
23 if consecutive_length[i] >= k:
24 result.append(nums[i])
25 else:
26 result.append(-1)
27
28 return result
29
1class Solution {
2 public int[] resultsArray(int[] nums, int k) {
3 int n = nums.length;
4
5 // Array to store the length of consecutive increasing sequence ending at each index
6 int[] consecutiveLength = new int[n];
7 Arrays.fill(consecutiveLength, 1);
8
9 // Build the consecutive length array
10 // For each position, check if it continues the consecutive sequence from previous position
11 for (int i = 1; i < n; ++i) {
12 if (nums[i] == nums[i - 1] + 1) {
13 // Current element is exactly 1 more than previous, extend the sequence
14 consecutiveLength[i] = consecutiveLength[i - 1] + 1;
15 }
16 }
17
18 // Initialize result array to store the answer for each subarray of size k
19 int[] result = new int[n - k + 1];
20
21 // Check each subarray of size k
22 for (int i = k - 1; i < n; ++i) {
23 // If the consecutive length at the end of current subarray >= k,
24 // then the subarray contains k consecutive elements, return the last element
25 // Otherwise, return -1
26 result[i - k + 1] = consecutiveLength[i] >= k ? nums[i] : -1;
27 }
28
29 return result;
30 }
31}
32
1class Solution {
2public:
3 vector<int> resultsArray(vector<int>& nums, int k) {
4 int n = nums.size();
5
6 // Array to store the length of consecutive increasing sequence ending at index i
7 int consecutiveLength[n];
8
9 // Base case: first element always has consecutive length of 1
10 consecutiveLength[0] = 1;
11
12 // Build the consecutive length array
13 // For each position, check if current element is exactly 1 more than previous
14 for (int i = 1; i < n; ++i) {
15 if (nums[i] == nums[i - 1] + 1) {
16 // Extend the consecutive sequence
17 consecutiveLength[i] = consecutiveLength[i - 1] + 1;
18 } else {
19 // Start a new consecutive sequence
20 consecutiveLength[i] = 1;
21 }
22 }
23
24 // Build the result array
25 vector<int> result;
26
27 // Check each window of size k
28 for (int i = k - 1; i < n; ++i) {
29 // If the consecutive length at the end of window is at least k,
30 // the entire window is consecutive, so return the last element
31 // Otherwise, return -1
32 if (consecutiveLength[i] >= k) {
33 result.push_back(nums[i]);
34 } else {
35 result.push_back(-1);
36 }
37 }
38
39 return result;
40 }
41};
42
1/**
2 * Finds the maximum element in each consecutive subarray of size k,
3 * but only if the subarray contains k consecutive integers.
4 * @param nums - The input array of numbers
5 * @param k - The size of the sliding window
6 * @returns An array where each element is either the max of a valid consecutive subarray or -1
7 */
8function resultsArray(nums: number[], k: number): number[] {
9 const arrayLength: number = nums.length;
10
11 // Array to track the length of consecutive sequences ending at each index
12 const consecutiveCount: number[] = Array(arrayLength).fill(1);
13
14 // Build the consecutive count array
15 // consecutiveCount[i] represents how many consecutive integers end at index i
16 for (let i = 1; i < arrayLength; ++i) {
17 // Check if current element is exactly 1 more than previous element
18 if (nums[i] === nums[i - 1] + 1) {
19 // Extend the consecutive sequence
20 consecutiveCount[i] = consecutiveCount[i - 1] + 1;
21 }
22 }
23
24 // Store the results for each window
25 const results: number[] = [];
26
27 // Process each window of size k
28 for (let windowEndIndex = k - 1; windowEndIndex < arrayLength; ++windowEndIndex) {
29 // Check if the window ending at windowEndIndex contains k consecutive integers
30 if (consecutiveCount[windowEndIndex] >= k) {
31 // If yes, the maximum element is the last element (since they're consecutive)
32 results.push(nums[windowEndIndex]);
33 } else {
34 // If not, push -1 to indicate invalid window
35 results.push(-1);
36 }
37 }
38
39 return results;
40}
41
Time and Space Complexity
The time complexity is O(n)
, where n
represents the length of the array nums
. The algorithm iterates through the array once to build the f
array (taking O(n)
time), and then performs another iteration to construct the result list using list comprehension (also taking O(n)
time). The total time complexity is O(n) + O(n) = O(n)
.
The space complexity is O(n)
. The algorithm creates an auxiliary array f
of size n
to store the consecutive sequence lengths, which requires O(n)
space. Additionally, the output list has size n - k + 1
, which is also O(n)
in the worst case. Therefore, the total space complexity is O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding the Consecutive Sequence Tracking
Pitfall: A common mistake is thinking that consecutive_length[i]
needs to track the entire subarray's validity rather than just the length of consecutive increasing sequence ending at position i
.
Wrong Approach:
# Incorrectly trying to check each subarray individually
for i in range(n - k + 1):
is_valid = True
for j in range(i, i + k - 1):
if nums[j + 1] != nums[j] + 1:
is_valid = False
break
result.append(nums[i + k - 1] if is_valid else -1)
Why it's wrong: This approach has O(n*k) time complexity and doesn't leverage the overlapping nature of subarrays.
Solution: Trust the preprocessing approach - if a sequence of length k
ends at position i
, then the subarray from i-k+1
to i
is valid.
2. Off-by-One Errors in Index Calculation
Pitfall: Confusion about which indices represent the start vs. end of subarrays, leading to incorrect range calculations.
Wrong Approach:
# Incorrect index range for results
return [nums[i] if consecutive_length[i] >= k else -1 for i in range(k, n + 1)] # Wrong!
Why it's wrong: The valid ending positions for subarrays of size k
are from index k-1
to n-1
, not k
to n
.
Solution: Remember that:
- First subarray: indices [0, k-1], ending at k-1
- Last subarray: indices [n-k, n-1], ending at n-1
- Total number of subarrays: n - k + 1
3. Incorrect Initialization of Consecutive Length Array
Pitfall: Initializing the consecutive length array to 0 instead of 1.
Wrong Approach:
consecutive_length = [0] * n # Wrong initialization!
Why it's wrong: Every element forms at least a sequence of length 1 by itself. Starting with 0 would incorrectly handle single-element sequences and propagate errors.
Solution: Always initialize to 1, as each element is a valid sequence of length 1:
consecutive_length = [1] * n
4. Not Handling Edge Cases Properly
Pitfall: Failing to consider special cases like k=1 or when the array has only one element.
Example Issue:
# This might fail when k=1 because the loop doesn't execute
for i in range(1, n):
if nums[i] == nums[i - 1] + 1:
consecutive_length[i] = consecutive_length[i - 1] + 1
# When k=1, every single element should return itself as power
Solution: The current implementation actually handles k=1 correctly because:
- consecutive_length is initialized with all 1s
- When k=1, every position i where i >= 0 satisfies consecutive_length[i] >= 1
- The result correctly returns each element itself
5. Confusing Consecutive with Sorted
Pitfall: Checking only if elements are sorted in ascending order without verifying they differ by exactly 1.
Wrong Approach:
# Only checking if sorted, not if consecutive if nums[i] > nums[i - 1]: # Wrong! Should be nums[i] == nums[i - 1] + 1 consecutive_length[i] = consecutive_length[i - 1] + 1
Why it's wrong: [2, 4, 6] is sorted but not consecutive. The problem requires elements to be both sorted AND consecutive (differ by exactly 1).
Solution: Always use the strict equality check:
if nums[i] == nums[i - 1] + 1: # Correct - ensures exactly 1 difference
Given a sorted array of integers and an integer called target, find the element that
equals to the target and return its index. Select the correct code that fills the
___
in the given code snippet.
1def binary_search(arr, target):
2 left, right = 0, len(arr) - 1
3 while left ___ right:
4 mid = (left + right) // 2
5 if arr[mid] == target:
6 return mid
7 if arr[mid] < target:
8 ___ = mid + 1
9 else:
10 ___ = mid - 1
11 return -1
12
1public static int binarySearch(int[] arr, int target) {
2 int left = 0;
3 int right = arr.length - 1;
4
5 while (left ___ right) {
6 int mid = left + (right - left) / 2;
7 if (arr[mid] == target) return mid;
8 if (arr[mid] < target) {
9 ___ = mid + 1;
10 } else {
11 ___ = mid - 1;
12 }
13 }
14 return -1;
15}
16
1function binarySearch(arr, target) {
2 let left = 0;
3 let right = arr.length - 1;
4
5 while (left ___ right) {
6 let mid = left + Math.trunc((right - left) / 2);
7 if (arr[mid] == target) return mid;
8 if (arr[mid] < target) {
9 ___ = mid + 1;
10 } else {
11 ___ = mid - 1;
12 }
13 }
14 return -1;
15}
16
Recommended Readings
https assets algo monster cover_photos stack svg Sliding Window Maximum Monotonic Stack We have an array and a sliding window defined by a start index and an end index The sliding window moves from left of the array to right There are always k elements in the window The window
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!