【LEETCODE OJ】Candy

Posted on 2014-04-06 23:30  卢泽尔  阅读(236)  评论(0编辑  收藏  举报

Problem link:

http://oj.leetcode.com/problems/candy/

 

Suppose we are given an array R[1..N] that are ratings of N children.

Let C[1..N] be a new array where C[i] is the number of candies for i-th child.

From the description, C[i] should meet following requirements:

LEAST. C[i] is at least 1, for i = 1, ..., N

LEFT. C[i] > C[i-1] if R[i] > R[i-1], for i = 2, ..., N

RIGHT. C[i] > C[i+1] if R[i] > R[i+1], for i = 1, ..., N-1

Each C[i] should satisfy these three requirements, excpet that C[1] only needs to meet LEAST and RIGHT and C[N] only needs to meet LEAST and LEFT.

To get the minimum number of candies, we desgin the following algorithm:

  1. Initialize the array C[1..N] with value of 1
  2. Scan the array R from left to right, and update C[] to meet LEFT.  That is, for each i = 2 to N,
    • if R[i] > R[i-1], then C[i] = C[i+1]
    • else, keep C[i] = 1
  3. Now, C[] satisfies LEAST and LEFT. Then scan the array R from right to left, update C[] not only meeting RIGHT but also keeping LEFT satisfied. That is, for each i = N-1 to 1,
    • if R[i] > R[i+1], then C[i] = max(C[i], C[i+1]+1)
    • else, keep C[i] unchanged

The algorithm computes C[] satisfying LEAST, LEFT, and RIGHT requirements. Since each time we increment C[i] by 1 to meet LEFT or RIGHT, so the total sum of C[] should be minimum (not sure how to prove the correctness, maybe a contradiction method needed). The algorithm can be finished in O(n) time. And the following code is the python solution accepted by oj.leetcode.com.

class Solution:
    # @param ratings, a list of integer
    # @return an integer
    def candy(self, ratings):
        # Specail cases
        n = len(ratings)
        if n < 2:
            return n
        
        # First scan, from left to right
        # only consider the following LEFT conditions:
        # if one's rating is higher than his left neighbor,
        # then he should have more candies than his left neighbor
        c = [0] * n
        c[0] = 1
        for p in xrange(1,n):
            if ratings[p] > ratings[p-1]:
                c[p] = c[p-1] + 1
            else:
                c[p] = 1
        
        # Second scan, from right to left
        # consider both RIGHT and LEFT conditions:
        # if c[p]'s rating is higher than his right neighbor,
        # then c[p] = max(c[p], c[p+1]+1), otherwise keep c[p] unchagned
        for p in xrange(n-2, -1, -1):
            if ratings[p] > ratings[p+1]:
                c[p] = max(c[p], c[p+1]+1)
        
        # Return the sum
        return sum(c)