Search code examples
c++algorithmrosetta-code

Equilibrium Index - What's wrong with my solution?


I have taken this example test before I'll try to take the real one for a job interview. The challenge is to implement the Equilibrium Index problem correctly.
I have coded some sort of solution that works only for the simple example and some of the edge cases.
Here's the code:

typedef vector<int> container_t;
typedef container_t::const_iterator iterator_t;

int find_equilibrium(const container_t &A);

int equi (const container_t &A)
{
    const std::size_t length = A.size();
    if (length  == 0)
        return -1;

    if (length == 1 && A[0] == 0)
        return -1;

    if (length == 1 && A[0] != 0)
        return 0;

    return find_equilibrium(A);
}

int find_equilibrium(const container_t &A)
{
    unsigned int i = 0;
    int sum = 0;

    for (iterator_t iter = A.begin(); iter != A.end(); ++iter, ++i)
    {
        sum += *iter; // not using std::accumulate to avoid N^2

        if (sum == 0)
            return i + 1;
    }

    return -1;
}

It is however fatally flawed for cases like [2, -2]. It does however for some reason avoid arithmetic_overflow exception. After Googling, I found the algorithm to be different then my own:

#include <numeric>
typedef vector<int> container_t;
typedef container_t::const_iterator iterator_t;

int find_equilibrium(const container_t &A);

int equi (const container_t &A)
{
    const std::size_t length = A.size();
    if (length  == 0)
        return -1;

    if (length == 1)
        return 0;

    return find_equilibrium(A);
}

int find_equilibrium(const container_t &A)
{
  unsigned int i = 0;
  int left = 0, right = std::accumulate(A.begin(), A.end(), 0);

  for (iterator_t iter = A.begin(); iter != A.end(); ++iter, ++i)
  {
    right -= *iter;

    if (left == right)
      return i;

    left += *iter;
  }

  return -1;
}

This code fails with extremely large numbers but works otherwise. I have no idea why though.

My questions are:

  • What's wrong with the way I was approaching this and how can I approach a different question of this type more correctly within a time limit of 30 minutes?
  • What really are all the corner cases for this problem exactly?
  • How can I score 100 for this example test?

Solution

  • Your logic it's right.

    A[0] + A[1] + A[2] = A[3] + A[4] + A[5] is equivalent to A[0] + A[1] + A[2] - (A[3] + A[4] + A[5]) = 0

    However, in your code, in the loop you add the values all the time, you never change the sign for those in the other half.

    for (iterator_t iter = A.begin(); iter != A.end(); ++iter, ++i) {
      sum += *iter; // only increasing, where do you subtract the values of the second half?
      if (sum == 0)
        return i + 1; // from the initial value you return the next index that gives you zero sum
    }