Given a 0-indexed integer array nums
, find the leftmost middleIndex
(i.e., the smallest amongst all the possible ones).
A middleIndex
is an index where nums[0] + nums[1] + ... + nums[middleIndex-1] == nums[middleIndex+1] + nums[middleIndex+2] + ... + nums[nums.length-1]
.
If middleIndex == 0
, the left side sum is considered to be 0
. Similarly, if middleIndex == nums.length - 1
, the right side sum is considered to be 0
.
Return the leftmost middleIndex
that satisfies the condition, or -1
if there is no such index.
Example 1:
Input: nums = [2,3,-1,8,4]
Output: 3
Explanation: The sum of the numbers before index 3 is: 2 + 3 + -1 = 4. The sum of the numbers after index 3 is: 4 = 4
Example 2:
Input: nums = [1,-1,4]
Output: 2
Explanation: The sum of the numbers before index 2 is: 1 + -1 = 0. The sum of the numbers after index 2 is: 0
Example 3:
Input: nums = [2,5]
Output: -1
Explanation: There is no valid middleIndex.
Consider the time and space complexity. Detail the edge cases and explain your logic clearly. Provide code samples in Python.
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We're figuring out where the middle is by exhaustively checking. We'll consider every single spot in the list as a possible middle, one at a time. For each spot, we'll compare the 'weight' on the left to the 'weight' on the right.
Here's how the algorithm would work step-by-step:
def find_middle_index_brute_force(numbers):
for potential_middle_index in range(len(numbers)):
left_sum = 0
for index_on_left in range(potential_middle_index):
left_sum += numbers[index_on_left]
# Reset the right sum for each middle index
right_sum = 0
for index_on_right in range(potential_middle_index + 1, len(numbers)):
right_sum += numbers[index_on_right]
# Check sums, we found the middle
if left_sum == right_sum:
return potential_middle_index
# No middle found, weights never match
return -1
The key is to avoid redundant calculations. Instead of repeatedly summing sections of the collection, we calculate a cumulative sum from one side and use that to efficiently derive sums from the opposite side when needed.
Here's how the algorithm would work step-by-step:
def find_middle_index(numbers):
total_sum = sum(numbers)
running_sum = 0
for i, number in enumerate(numbers):
# Check if left sum equals right sum
if running_sum == (total_sum - running_sum - number):
return i
# Keep a running sum of the left side
running_sum += number
# If no middle index is found
return -1
Case | How to Handle |
---|---|
Null or empty array input | Return -1 immediately, as a middle index cannot exist in an empty array. |
Array with only one element | Return 0 as the first and only element satisfies the condition of having equal sum on both sides. |
Array with all elements equal to zero | Return 0 as the first index since the sum on both sides will always be 0. |
Array with a large number of elements (performance considerations) | Use a prefix sum approach for O(n) time complexity to efficiently handle large arrays. |
Integer overflow when calculating sums, especially with large positive or negative numbers | Use long data type to store sums to prevent potential integer overflows. |
Array where no middle index exists | Return -1 after iterating through the entire array and not finding a suitable middle index. |
Array with negative numbers | The algorithm should handle negative numbers correctly since it's based on calculating sums. |
Array with extreme boundary values (Integer.MAX_VALUE, Integer.MIN_VALUE) | Using long avoids overflow which would be relevant in boundary value calculations. |