Intuition

My thought was first going left to right checking both neighbours. For example, for [1,2,3,4] would work perfectly.

However it’s not possible to solve this in one pass checking both neighbours. We need to use a two pass approach, LTR, RTL.

To visualize better the problem, using [1,2,3,4] let’s see how many candies LTR and RTL would give for each children:

LTR
[1,2,3,4] -> [1,2,3,4]
since it's always increase each children get's one more candy than the previous one.

RTL
[1,2,3,4] -> [1,1,1,1]
From RTL perspective, it's always decreasing, so all children get's one.

In this case the correct solution is [1,2,3,4]

Now, let’s see this other example [3,2,1,2,3]

LTR
[3,2,1,2,3] -> [1,1,1,2,3]

RTL
[3,2,1,2,3] -> [3,2,1,1,1]

The solution here the the max between the two arrays.

Approach

Initilize two arrays, L and R with one element. From left to right check if the current element is greater than the previous one, if it is, this child has previous+1 candies.

We do the same right to left (reversed loop), check if the current element if greater than the next one, if it is, this child has next+1 candies.

The answer is the max of each arrays’ element.

Complexity

  • Time complexity: O(n)
    • linear time, 3 passes (ltr, rtl, answer)
  • Space complexity: O(n)
    • two control arrays

Code

class Solution(object):
    def candy(self, ratings):
        """
        :type ratings: List[int]
        :rtype: int
        """

        L = [1] * len(ratings)
        R = [1] * len(ratings)

        for i in range(1, len(ratings)):
            if ratings[i] > ratings[i-1]:
                L[i] = L[i-1] + 1

        for i in reversed(range(0, len(ratings)-1)):
            if ratings[i] > ratings[i+1]:
                R[i] = R[i+1] + 1

        return sum(max(R[i],L[i]) for i in range(len(L)))