Facebook Pixel

3284. Sum of Consecutive Subarrays

Problem Description

You need to find all consecutive subarrays in an array and calculate the sum of their values.

A subarray is called consecutive if it follows one of these patterns:

  • Each element is exactly 1 more than the previous element (increasing by 1), like [3, 4, 5]
  • Each element is exactly 1 less than the previous element (decreasing by 1), like [9, 8, 7]

The value of an array is simply the sum of all its elements. For example:

  • [3, 4, 5] has value 12 (3 + 4 + 5)
  • [9, 8] has value 17 (9 + 8)
  • [3, 4, 3] is NOT consecutive (4 to 3 is -1, but 3 to 4 is +1, not consistent)
  • [8, 6] is NOT consecutive (difference is -2, not -1)

Given an array nums, you need to:

  1. Find all possible subarrays that are consecutive
  2. Calculate the value (sum) of each consecutive subarray
  3. Return the total sum of all these values

Important notes:

  • A single element by itself counts as a consecutive subarray
  • The result should be returned modulo 10^9 + 7 to handle large numbers
  • A subarray is a contiguous part of the array (elements must be adjacent in the original array)

For example, if nums = [1, 2, 3]:

  • Consecutive subarrays are: [1], [2], [3], [1,2], [2,3], [1,2,3]
  • Their values are: 1, 2, 3, 3, 5, 6
  • Total sum = 1 + 2 + 3 + 3 + 5 + 6 = 20
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that we need to track consecutive subarrays efficiently without checking every possible subarray, which would be too slow.

Think about what happens as we traverse the array element by element. At each position, we need to know:

  • Which consecutive subarrays can be extended to include the current element
  • Which new consecutive subarrays start at the current element

When we move from nums[i-1] to nums[i], there are only three possibilities:

  1. nums[i] - nums[i-1] == 1: The current element continues an increasing sequence
  2. nums[i] - nums[i-1] == -1: The current element continues a decreasing sequence
  3. Neither: The current element breaks any consecutive pattern

This observation leads us to maintain two separate tracking mechanisms:

  • For increasing consecutive subarrays (difference of +1)
  • For decreasing consecutive subarrays (difference of -1)

For each type, we need to track:

  • Length (f for increasing, g for decreasing): How many consecutive subarrays of this type end at the current position
  • Sum (s for increasing, t for decreasing): The total sum of all these subarrays

Why track the length? Because when we extend a consecutive sequence by one element, we're not just adding one new subarray - we're adding multiple subarrays. For example, if we have [1, 2] and add 3, we get:

  • The subarray [3] (always counts)
  • The subarray [2, 3] (extending from previous element)
  • The subarray [1, 2, 3] (extending the full sequence)

The number of subarrays we extend equals the length of the current consecutive sequence. Each of these subarrays includes the new element, so we add length × current_element to our running sum.

By maintaining these values as we traverse the array once, we can efficiently calculate the total sum of all consecutive subarrays without redundant work.

Learn more about Two Pointers and Dynamic Programming patterns.

Solution Approach

We implement the solution using dynamic programming with state tracking as we traverse the array once.

Variables Setup:

  • f: Length of the increasing consecutive subarray ending at current position
  • g: Length of the decreasing consecutive subarray ending at current position
  • s: Sum of all increasing consecutive subarrays ending at current position
  • t: Sum of all decreasing consecutive subarrays ending at current position
  • ans: Accumulator for the final answer
  • mod = 10^9 + 7: For modulo operation

Initialization:

  • Set f = g = 1 (single element forms a consecutive subarray of length 1)
  • Set s = t = nums[0] (initial sum is just the first element)
  • Set ans = nums[0] (first element contributes to answer)

Main Algorithm:

For each pair of consecutive elements (x, y) where x = nums[i-1] and y = nums[i]:

  1. Check for increasing sequence (y - x == 1):

    • Increment f by 1 (extending the increasing sequence length)
    • Update s by adding f * y (all f subarrays now include y)
    • Add s to answer (all increasing subarrays ending at y)
    • If not increasing, reset: f = 1, s = y
  2. Check for decreasing sequence (y - x == -1):

    • Increment g by 1 (extending the decreasing sequence length)
    • Update t by adding g * y (all g subarrays now include y)
    • Add t to answer (all decreasing subarrays ending at y)
    • If not decreasing, reset: g = 1, t = y
  3. Handle non-consecutive case (abs(y - x) != 1):

    • Add y to answer (single element forms a consecutive subarray)

Why the formula s += f * y works:

When extending an increasing sequence, we have f different subarrays ending at position i:

  • The subarray of length 1: just [y]
  • The subarray of length 2: [x, y]
  • The subarray of length 3: [..., x, y]
  • And so on...

Each of these f subarrays includes the new element y, so we add f * y to the sum.

Time Complexity: O(n) - single pass through the array Space Complexity: O(1) - only using constant extra variables

The algorithm efficiently computes the sum by maintaining running totals and lengths of consecutive sequences, avoiding the need to explicitly enumerate all subarrays.

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 the solution with nums = [1, 2, 3, 5].

Initial State:

  • Start with first element: nums[0] = 1
  • f = 1, g = 1 (length of increasing/decreasing sequences)
  • s = 1, t = 1 (sum of increasing/decreasing subarrays)
  • ans = 1 (contribution from [1])

Step 1: Process nums[1] = 2

  • Previous: x = 1, Current: y = 2
  • Difference: 2 - 1 = 1 (increasing!)

Increasing sequence update:

  • f = f + 1 = 2 (now have 2 consecutive subarrays: [2] and [1,2])
  • s = s + f * y = 1 + 2 * 2 = 5 (sum of [2]=2 and [1,2]=3)
  • ans = ans + s = 1 + 5 = 6

Decreasing sequence update:

  • Not decreasing, so reset: g = 1, t = 2
  • No contribution to answer

Step 2: Process nums[2] = 3

  • Previous: x = 2, Current: y = 3
  • Difference: 3 - 2 = 1 (increasing!)

Increasing sequence update:

  • f = f + 1 = 3 (now have 3 subarrays: [3], [2,3], [1,2,3])
  • s = s + f * y = 5 + 3 * 3 = 14 (sum of [3]=3, [2,3]=5, [1,2,3]=6)
  • ans = ans + s = 6 + 14 = 20

Decreasing sequence update:

  • Not decreasing, so reset: g = 1, t = 3
  • No contribution to answer

Step 3: Process nums[3] = 5

  • Previous: x = 3, Current: y = 5
  • Difference: 5 - 3 = 2 (not consecutive!)

Since it's not consecutive (neither +1 nor -1):

  • Reset both sequences: f = 1, s = 5, g = 1, t = 5
  • Add single element: ans = ans + y = 20 + 5 = 25

Final Answer: 25

Let's verify by listing all consecutive subarrays:

  • [1] → sum = 1
  • [2] → sum = 2
  • [3] → sum = 3
  • [5] → sum = 5
  • [1,2] → sum = 3
  • [2,3] → sum = 5
  • [1,2,3] → sum = 6

Total = 1 + 2 + 3 + 5 + 3 + 5 + 6 = 25 ✓

The algorithm efficiently computes this by tracking running sums and lengths of consecutive sequences, avoiding the need to explicitly check every possible subarray.

Solution Implementation

1class Solution:
2    def getSum(self, nums: List[int]) -> int:
3        MOD = 10**9 + 7
4
5        # Initialize counters for increasing and decreasing sequences
6        increasing_length = 1  # Length of current increasing sequence (diff = 1)
7        decreasing_length = 1  # Length of current decreasing sequence (diff = -1)
8
9        # Initialize cumulative sums for sequences
10        increasing_sum = nums[0]  # Cumulative sum for increasing sequence
11        decreasing_sum = nums[0]  # Cumulative sum for decreasing sequence
12
13        # Initialize the answer with the first element
14        result = nums[0]
15
16        # Iterate through consecutive pairs of elements
17        for prev_num, curr_num in pairwise(nums):
18            diff = curr_num - prev_num
19
20            # Handle increasing sequence (difference of exactly 1)
21            if diff == 1:
22                increasing_length += 1
23                # Add current number weighted by its position in the sequence
24                increasing_sum += increasing_length * curr_num
25                result = (result + increasing_sum) % MOD
26            else:
27                # Reset increasing sequence
28                increasing_length = 1
29                increasing_sum = curr_num
30
31            # Handle decreasing sequence (difference of exactly -1)
32            if diff == -1:
33                decreasing_length += 1
34                # Add current number weighted by its position in the sequence
35                decreasing_sum += decreasing_length * curr_num
36                result = (result + decreasing_sum) % MOD
37            else:
38                # Reset decreasing sequence
39                decreasing_length = 1
40                decreasing_sum = curr_num
41
42            # Handle non-consecutive elements (neither +1 nor -1 difference)
43            if abs(diff) != 1:
44                result = (result + curr_num) % MOD
45
46        return result
47
1class Solution {
2    public int getSum(int[] nums) {
3        final int MOD = (int) 1e9 + 7;
4
5        // sumIncreasing: cumulative sum for increasing sequences (diff = 1)
6        long sumIncreasing = nums[0];
7        // sumDecreasing: cumulative sum for decreasing sequences (diff = -1)
8        long sumDecreasing = nums[0];
9        // totalSum: accumulator for the final result
10        long totalSum = nums[0];
11
12        // countIncreasing: count of consecutive elements in increasing sequence
13        int countIncreasing = 1;
14        // countDecreasing: count of consecutive elements in decreasing sequence
15        int countDecreasing = 1;
16
17        for (int i = 1; i < nums.length; ++i) {
18            int previousValue = nums[i - 1];
19            int currentValue = nums[i];
20            int difference = currentValue - previousValue;
21
22            // Handle increasing sequence (difference = 1)
23            if (difference == 1) {
24                // Extend the increasing sequence
25                ++countIncreasing;
26                // Add weighted contribution of current value
27                sumIncreasing += (long) countIncreasing * currentValue;
28                totalSum = (totalSum + sumIncreasing) % MOD;
29            } else {
30                // Reset increasing sequence
31                countIncreasing = 1;
32                sumIncreasing = currentValue;
33            }
34
35            // Handle decreasing sequence (difference = -1)
36            if (difference == -1) {
37                // Extend the decreasing sequence
38                ++countDecreasing;
39                // Add weighted contribution of current value
40                sumDecreasing += (long) countDecreasing * currentValue;
41                totalSum = (totalSum + sumDecreasing) % MOD;
42            } else {
43                // Reset decreasing sequence
44                countDecreasing = 1;
45                sumDecreasing = currentValue;
46            }
47
48            // For non-consecutive elements (|difference| != 1), add single value
49            if (Math.abs(difference) != 1) {
50                totalSum = (totalSum + currentValue) % MOD;
51            }
52        }
53
54        return (int) totalSum;
55    }
56}
57
1class Solution {
2public:
3    int getSum(vector<int>& nums) {
4        const int MOD = 1e9 + 7;
5
6        // Variables for tracking increasing sequences (difference of +1)
7        long long increasingSum = nums[0];  // Sum of current increasing sequence
8        int increasingLength = 1;            // Length of current increasing sequence
9
10        // Variables for tracking decreasing sequences (difference of -1)
11        long long decreasingSum = nums[0];  // Sum of current decreasing sequence
12        int decreasingLength = 1;            // Length of current decreasing sequence
13
14        // Initialize answer with first element
15        long long answer = nums[0];
16
17        // Process each element starting from index 1
18        for (int i = 1; i < nums.size(); ++i) {
19            int previousNum = nums[i - 1];
20            int currentNum = nums[i];
21            int difference = currentNum - previousNum;
22
23            // Handle increasing sequence (difference == 1)
24            if (difference == 1) {
25                // Extend the increasing sequence
26                ++increasingLength;
27                // Add contribution of current number to the sequence sum
28                // Each number contributes based on its position in the sequence
29                increasingSum += 1LL * increasingLength * currentNum;
30                answer = (answer + increasingSum) % MOD;
31            } else {
32                // Reset increasing sequence
33                increasingLength = 1;
34                increasingSum = currentNum;
35            }
36
37            // Handle decreasing sequence (difference == -1)
38            if (difference == -1) {
39                // Extend the decreasing sequence
40                ++decreasingLength;
41                // Add contribution of current number to the sequence sum
42                decreasingSum += 1LL * decreasingLength * currentNum;
43                answer = (answer + decreasingSum) % MOD;
44            } else {
45                // Reset decreasing sequence
46                decreasingLength = 1;
47                decreasingSum = currentNum;
48            }
49
50            // If neither increasing nor decreasing by 1, add the current number once
51            if (abs(difference) != 1) {
52                answer = (answer + currentNum) % MOD;
53            }
54        }
55
56        return answer;
57    }
58};
59
1/**
2 * Calculates the sum of subsequences based on specific difference patterns
3 * @param nums - Array of numbers to process
4 * @returns The sum modulo 10^9 + 7
5 */
6function getSum(nums: number[]): number {
7    const MOD: number = 10 ** 9 + 7;
8
9    // Track consecutive increasing sequences (difference of 1)
10    let increasingLength: number = 1;
11    let increasingSum: number = nums[0];
12
13    // Track consecutive decreasing sequences (difference of -1)
14    let decreasingLength: number = 1;
15    let decreasingSum: number = nums[0];
16
17    // Initialize answer with first element
18    let answer: number = nums[0];
19
20    // Process each element starting from index 1
21    for (let i = 1; i < nums.length; i++) {
22        const previousNum: number = nums[i - 1];
23        const currentNum: number = nums[i];
24        const difference: number = currentNum - previousNum;
25
26        // Handle increasing sequence (difference equals 1)
27        if (difference === 1) {
28            increasingLength++;
29            increasingSum += increasingLength * currentNum;
30            answer = (answer + increasingSum) % MOD;
31        } else {
32            // Reset increasing sequence tracking
33            increasingLength = 1;
34            increasingSum = currentNum;
35        }
36
37        // Handle decreasing sequence (difference equals -1)
38        if (difference === -1) {
39            decreasingLength++;
40            decreasingSum += decreasingLength * currentNum;
41            answer = (answer + decreasingSum) % MOD;
42        } else {
43            // Reset decreasing sequence tracking
44            decreasingLength = 1;
45            decreasingSum = currentNum;
46        }
47
48        // Add current number to answer if difference is not 1 or -1
49        if (Math.abs(difference) !== 1) {
50            answer = (answer + currentNum) % MOD;
51        }
52    }
53
54    return answer;
55}
56

Time and Space Complexity

The time complexity is O(n), where n is the length of the array nums. The algorithm iterates through the array once using pairwise(nums), which generates consecutive pairs of elements. Since pairwise yields n-1 pairs for an array of length n, and each iteration performs a constant number of operations (comparisons, arithmetic operations, and modulo operations), the overall time complexity is linear.

The space complexity is O(1). The algorithm uses only a fixed number of variables (mod, f, g, s, t, ans, x, y) regardless of the input size. The pairwise function is a generator that doesn't create additional data structures, it only yields pairs one at a time. Therefore, the space usage remains constant throughout the execution.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Handling of Sequence Resets

The Pitfall: When a sequence breaks (difference is not ±1), developers often forget that the current element still starts a new consecutive subarray of length 1. A common mistake is to only reset the counters without properly accounting for the current element's contribution.

Incorrect Implementation:

if diff == 1:
    increasing_length += 1
    increasing_sum += increasing_length * curr_num
    result = (result + increasing_sum) % MOD
else:
    # WRONG: Forgetting to add curr_num when it's not part of increasing sequence
    increasing_length = 1
    increasing_sum = 0  # Should be curr_num, not 0!

The Solution: Always initialize the sum with the current element when resetting, as every single element forms a valid consecutive subarray:

else:
    increasing_length = 1
    increasing_sum = curr_num  # Correct: current element starts new sequence

2. Double Counting When Difference is Neither +1 nor -1

The Pitfall: The current implementation has a subtle issue where elements are added multiple times when the difference is neither +1 nor -1. The element gets added through both the increasing and decreasing reset operations, plus the explicit non-consecutive check.

Example Problem: For array [1, 3, 5]:

  • When processing 3 (diff = 2):
    • Reset increasing: adds 3 to increasing_sum
    • Reset decreasing: adds 3 to decreasing_sum
    • Non-consecutive check: adds 3 again
  • This leads to overcounting

The Solution: Track whether we've already counted the current element:

for prev_num, curr_num in pairwise(nums):
    diff = curr_num - prev_num
    counted = False

    if diff == 1:
        increasing_length += 1
        increasing_sum += increasing_length * curr_num
        result = (result + increasing_sum) % MOD
        counted = True
    else:
        increasing_length = 1
        increasing_sum = curr_num

    if diff == -1:
        decreasing_length += 1
        decreasing_sum += decreasing_length * curr_num
        result = (result + decreasing_sum) % MOD
        counted = True
    else:
        decreasing_length = 1
        decreasing_sum = curr_num

    # Only add if not already counted in a sequence
    if not counted:
        result = (result + curr_num) % MOD

3. Overflow Without Proper Modulo Operations

The Pitfall: Forgetting to apply modulo operations during intermediate calculations can cause integer overflow, especially when dealing with large arrays or values.

Incorrect Implementation:

increasing_sum += increasing_length * curr_num  # Can overflow
result = (result + increasing_sum) % MOD

The Solution: Apply modulo operations to intermediate calculations:

increasing_sum = (increasing_sum + increasing_length * curr_num) % MOD
result = (result + increasing_sum) % MOD

4. Missing Edge Case: Single Element Array

The Pitfall: The pairwise function won't iterate at all for single-element arrays, but the initialization correctly handles this case. However, if someone modifies the code structure, they might break this handling.

The Solution: Ensure the initialization properly handles single-element arrays and document this behavior:

# Handle single element case through initialization
result = nums[0]  # This ensures single element arrays return correct result
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