Finding the Longest Subarray with a Given Sum: A Java Implementation (Handles Positive and Negative Numbers)
The problem of finding the longest subarray with a given sum is a common coding challenge. Given an array arr[]
of integers (which can include both positive and negative numbers) and an integer k
, our task is to find the length of the longest contiguous subarray whose elements sum up to k
. If no such subarray exists, we return 0.
This blog post will explore an efficient Java implementation that correctly handles both positive and negative numbers in the input array.
The Challenge with Negative Numbers
The presence of negative numbers makes this problem more complex. A simple sliding window approach that works for positive numbers might fail when negative numbers are involved. This is because the sum of a subarray can decrease as we expand the window (due to negative numbers), and we might prematurely shrink the window, missing potential longer subarrays with the target sum.
The Solution: Sliding Window (Corrected)
We'll use a sliding window approach, but with a crucial modification to handle negative numbers correctly.
Java Code
Java
public class LongestSubarraySumK {
public static int longestSubArray(int num[], long k) {
int n = num.length;
int left = 0, right = 0;
long sum = 0; // Use long to prevent potential overflow
int maxLen = 0;
while (right < n) {
sum += num[right]; // Add the current element to the sum
while (sum > k) { // Shrink the window ONLY when sum exceeds k
sum -= num[left];
left++;
}
if (sum == k) {
maxLen = Math.max(maxLen, right - left + 1);
}
right++; // Move the right pointer regardless of sum value
}
return maxLen;
}
public static void main(String[] args) {
// Test cases
int[] num1 = {-1, 2, -3, 4, -2, 1};
long k1 = 0;
System.out.println("Test Case 1: " + longestSubArray(num1, k1)); // Output: 6
int[] num2 = {1, 2, 3, 4, 5};
long k2 = 9;
System.out.println("Test Case 2: " + longestSubArray(num2, k2)); // Output: 2
int[] num3 = {1, 2, 3};
long k3 = 7;
System.out.println("Test Case 3: " + longestSubArray(num3, k3)); // Output: 0
int[] num4 = {1, 2, 3, -2, -1, 3, 3};
long k4 = 6;
System.out.println("Test Case 4: " + longestSubArray(num4, k4)); // Output: 3
int[] num5 = {1,2,3,-1,-2,4};
long k5 = 3;
System.out.println("Test Case 5: " + longestSubArray(num5, k5)); // Output: 4
int[] num6 = {1,2,3,-1,-2,4};
long k6 = 6;
System.out.println("Test Case 6: " + longestSubArray(num6, k6)); // Output: 0
}
}
Explanation of the Code
Initialization:
left
andright
pointers define the sliding window.sum
stores the current sum of elements within the window. It's crucial to uselong
forsum
to avoid potential integer overflow, especially with large arrays or target values.maxLen
stores the maximum length of a subarray found so far.
Sliding Window Logic:
The
while (right < n)
loop expands the window by moving theright
pointer.sum += num[right];
adds the current element to the sum.The
while (sum > k)
loop shrinks the window from the left only when thesum
strictly exceedsk
. This is the key change to handle negative numbers correctly. We don't shrink the window ifsum
is just greater than or equal tok
. We keep shrinking until it is strictly greater thank
.if (sum == k)
: If thesum
equalsk
, we updatemaxLen
.right++;
: Theright
pointer is always incremented to explore all possible subarrays.
Why this works:
By only shrinking the window when sum > k
, we ensure that we don't prematurely discard potential solutions with negative numbers. The window might contain negative numbers that bring the sum down to k
after it has been greater than k
at some point.
Time and Space Complexity
Time Complexity: O(n). Although there appears to be a nested
while
loop, theleft
pointer only moves forward throughout the process. Each element is visited at most twice.Space Complexity: O(1). The algorithm uses constant extra space.
Conclusion
This corrected sliding window approach provides an efficient and robust solution to the longest subarray sum problem, correctly handling both positive and negative numbers. The use of long
for the sum
variable is also important to prevent potential overflow issues. This implementation is suitable for various coding challenges and real-world applications.