Facebook Pixel

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].

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

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 if nums[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)

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 set f[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 to n-1 (these are the ending positions of all possible subarrays of size k)
  • For each ending position i, if f[i] >= k, it means there are at least k consecutive increasing elements ending at position i, making the subarray valid
    • The power is nums[i] (the maximum element in the consecutive sequence)
  • 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 Evaluator

Example 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 and nums[0] = 1. Since 2 = 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 and nums[1] = 2. Since 3 = 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 and nums[2] = 3. Since 1 ≠ 3 + 1, not consecutive.
    No update needed (remains 1).
    Result: f = [1, 2, 3, 1, 1]

  • At index 4: nums[4] = 2 and nums[3] = 1. Since 2 = 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
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

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

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More