Difficulty: Easy, Asked-in: Amazon, Adobe, Hike.
Key takeaway: An excellent problem to learn problem-solving and step-by-step optimization using prefix array and single loop using variables.
Write a program to find the equilibrium index of an array. The equilibrium index of an array is an index such that the sum of elements at lower indexes is equal to the sum of elements at higher indexes.
In other words, the equilibrium index of an array is an index 'i' such that the sum of elements at indices less than 'i' is equal to the sum of elements at indices greater than 'i'. A[0] + A[1] + ... + A[i - 1] = A[i + 1] + ... + A[n - 1], where 0 <= i <= n - 1.
Problem note:
Input: A[] = [-7, 1, 5, 2, -4, 3, 0], Output: 3
Explanation: 3 is an equilibrium index, i.e., A[0] + A[1] + A[2] = A[4] + A[5] + A[6] = -1.
Input: A[] = [0, 1, 3, -2, -1], Output: 1
Explanation: 1 is an equilibrium index, i.e., A[0] = A[2] + A[3] + A[4] = 0.
Input: A[] = [1, 2, -2, -1], Output: -1
Explanation: There is no such equilibrium index in the array.
The basic idea is to explore each index i and find the sum of all elements on the left and right sides, excluding the value at index i. If both left and right sums are equal, the index i would be the equilibrium index.
We can use nested loops to implement this: the outer loop explores each index i, and the inner loop determines whether index i is an equilibrium index or not by calculating left and right sums. We use two extra variables: leftSum and rightSum to store the sum of elements on the left and right sides of the current index.
for(int j = 0; j < i; j = j + 1)
leftSum = leftSum + A[j]
for(int j = i + 1; j < n; j = j + 1)
rightSum = rightSum + A[j]
if(leftSum == rightSum)
return i
int equilibriumIndexArray(int A[], int n)
{
int leftSum, rightSum;
for (int i = 0; i < n; i = i + 1)
{
leftSum = 0;
for (int j = 0; j < i; j = j + 1)
leftSum = leftSum + A[j];
rightSum = 0;
for (int j = i + 1; j < n; j = j + 1)
rightSum = rightSum + A[j];
if (leftSum == rightSum)
return i;
}
return -1;
}
def equilibriumIndexArray(A, n):
leftSum = 0
rightSum = 0
for i in range(n):
leftSum = 0
for j in range(i):
leftSum = leftSum + A[j]
rightSum = 0
for j in range(i+1, n):
rightSum = rightSum + A[j]
if leftSum == rightSum:
return i
return -1
Inside the outer loop, summation is a critical operation that will define our time complexity.
Now the critical questions are: Can we improve the time complexity further? Can we do some pre-processing to avoid repeated calculations of leftSum and rightSum at each iteration of the outer loop? Let's think!
Suppose we store the prefix sum of the input array in an extra memory prefix[n], which keeps track of the sum of all elements up to any index i at prefix[i]. Using this prefix array, at each iteration of the outer loop, we can easily calculate leftSum and rightSum in O(1). How? Let's see!
int prefix[n];
prefix[0] = A[0];
for (int i = 1; i < n; i = i + 1)
prefix[i] = prefix[i - 1] + A[i];
for(int i = 0; i < n; i = i + 1)
{
int leftSum = prefix[i] - A[i]
int rightSum = totalSum - prefix[i]
if(leftSum == rightSum)
return i
}
int equilibriumIndexArray(int A[], int n)
{
int prefix[n];
prefix[0] = A[0];
for (int i = 1; i < n; i = i + 1)
prefix[i] = prefix[i - 1] + A[i];
int totalSum = prefix[n - 1];
for (int i = 0; i < n; i = i + 1)
{
int leftSum = prefix[i] - A[i];
int rightSum = totalSum - prefix[i];
if (leftSum == rightSum)
return i;
}
return -1;
}
def equilibrium_index_array(A, n):
prefix = [0] * n
prefix[0] = A[0]
for i in range(1, n):
prefix[i] = prefix[i - 1] + A[i]
total_sum = prefix[n - 1]
for i in range(n):
left_sum = prefix[i] - A[i]
right_sum = total_sum - prefix[i]
if left_sum == right_sum:
return i
return -1
We are running two separate loops to calculate the prefix sum array and the equilibrium index, respectively. The time complexity is equal to the time complexity of calculating the prefix sum array plus the time complexity of calculating the equilibrium index, which is O(n) + O(n) = O(n).
The above solution uses extra space to store the prefix sum array. The space complexity is O(n).
The critical question is: Can we improve space complexity further and solve the problem without using a prefix array? Can we track the values of leftSum and rightSum while traversing the array itself? Think!
Before starting the ith iteration of the loop, suppose we know the totalSum and the value of leftSum. Then, at the ith iteration:
for(int i = 0; i < n; i = i + 1)
totalSum = totalSum + A[i]
for(int i = 0; i < n; i = i + 1)
{
int rightSum = totalSum - leftSum - A[i]
if(leftSum == rightSum)
return i
leftSum = leftSum + A[i]
}
int equilibriumIndexArray(int A[], int n)
{
int totalSum = 0;
int leftSum = 0;
for (int i = 0; i < n; i = i + 1)
totalSum = totalSum + A[i];
for (int i = 0; i < n; i = i + 1)
{
int rightSum = totalSum - leftSum - A[i];
if (leftSum == rightSum)
return i;
leftSum = leftSum + A[i];
}
return -1;
}
def equilibriumIndexArray(A, n):
totalSum = 0
leftSum = 0
for i in range(n):
totalSum = totalSum + A[i]
for i in range(n):
rightSum = totalSum - leftSum - A[i]
if leftSum == rightSum:
return i
leftSum = leftSum + A[i]
return -1
We are using single loops and variables. So time complexity is O(n) and space complexity is O(1).
If you have any queries or feedback, please write us at contact@enjoyalgorithms.com. Enjoy learning, Enjoy algorithms!