Subarray of Given Sum II in O(n) Time Complexity using JavaScript


Given an array of integers and a number target, find a continous subarray whose sum is equal to target.

Return the start and end indices denoting this subarray. If there are multiple solutions, you can return any of them.


Example:

Input: nums = [1, 1, 5, 2, 1, 3, 10, 2, 1], k = 21
Output: [2, 6]
Explanation: 5 + 2 + 1 + 3 + 10 = 21

Notes:

1. The array can consist of positive and negative numbers.

2. Your algorithm should run in O(n) time and use O(n) extra space.


Problem Definition

The problem requires finding a continuous subarray within a given array of integers that sums up to a specified target value. The solution should return the start and end indices of this subarray. If there are multiple solutions, any one of them can be returned.

Input:

  • nums: An array of integers, which can include both positive and negative numbers.
  • target: An integer representing the target sum.

Output:

  • An array containing two integers representing the start and end indices of the subarray whose sum equals the target.

Constraints:

  • The algorithm should run in O(n) time complexity.
  • The algorithm should use O(n) extra space.

Example:

Input: nums = [1, 1, 5, 2, 1, 3, 10, 2, 1], target = 21
Output: [2, 6]
Explanation: 5 + 2 + 1 + 3 + 10 = 21

Understanding the Problem

The core challenge is to find a continuous subarray that sums up to the target value. This problem is significant in various applications such as financial analysis, where one might need to find a period with a specific sum of transactions.

Potential pitfalls include handling negative numbers and ensuring the solution runs efficiently within the given constraints.

Approach

To solve this problem, we can use a sliding window approach combined with a hash map to keep track of the cumulative sums. This approach ensures that we can find the subarray in O(n) time complexity.

Naive Solution

A naive solution would involve checking all possible subarrays and calculating their sums, which would result in O(n^2) time complexity. This is not optimal for large arrays.

Optimized Solution

The optimized solution involves using a hash map to store the cumulative sum up to each index. By doing this, we can quickly check if there is a subarray that sums to the target by looking for the difference between the current cumulative sum and the target in the hash map.

Algorithm

Here is a step-by-step breakdown of the optimized algorithm:

  1. Initialize a hash map to store the cumulative sums and their corresponding indices.
  2. Initialize a variable to keep track of the cumulative sum.
  3. Iterate through the array, updating the cumulative sum at each step.
  4. Check if the cumulative sum equals the target. If so, return the indices from the start to the current index.
  5. Check if the difference between the cumulative sum and the target exists in the hash map. If so, return the indices from the next index of the stored index to the current index.
  6. Store the current cumulative sum and its index in the hash map.

Code Implementation

/**
 * Function to find the subarray with a given sum.
 * @param {number[]} nums - The array of integers.
 * @param {number} target - The target sum.
 * @return {number[]} - The start and end indices of the subarray.
 */
function subarraySum(nums, target) {
    // Initialize a map to store cumulative sums and their indices
    const map = new Map();
    // Initialize the cumulative sum
    let cumulativeSum = 0;
    // Iterate through the array
    for (let i = 0; i < nums.length; i++) {
        // Update the cumulative sum
        cumulativeSum += nums[i];
        // Check if the cumulative sum equals the target
        if (cumulativeSum === target) {
            return [0, i];
        }
        // Check if the difference between cumulative sum and target exists in the map
        if (map.has(cumulativeSum - target)) {
            return [map.get(cumulativeSum - target) + 1, i];
        }
        // Store the cumulative sum and its index in the map
        map.set(cumulativeSum, i);
    }
    // Return an empty array if no subarray is found
    return [];
}

// Example usage
const nums = [1, 1, 5, 2, 1, 3, 10, 2, 1];
const target = 21;
console.log(subarraySum(nums, target)); // Output: [2, 6]

Complexity Analysis

The time complexity of this approach is O(n) because we iterate through the array once. The space complexity is also O(n) due to the hash map storing the cumulative sums.

Edge Cases

Potential edge cases include:

  • An empty array: The function should return an empty array.
  • All negative numbers: The function should handle negative sums correctly.
  • Multiple subarrays with the same sum: The function can return any valid subarray.

Testing

To test the solution comprehensively, consider the following test cases:

  • Simple cases with small arrays.
  • Cases with negative numbers.
  • Cases with multiple valid subarrays.
  • Edge cases such as empty arrays or arrays with a single element.

Thinking and Problem-Solving Tips

When approaching such problems, consider the following tips:

  • Break down the problem into smaller parts.
  • Think about different approaches and their time complexities.
  • Use hash maps or other data structures to optimize the solution.
  • Practice similar problems to improve problem-solving skills.

Conclusion

In this blog post, we discussed how to find a continuous subarray with a given sum in O(n) time complexity using JavaScript. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for improving problem-solving skills and preparing for coding interviews.

Additional Resources

For further reading and practice, consider the following resources: