|
| 1 | +# 135. Candy |
| 2 | +# 🔴 Hard |
| 3 | +# |
1 | 4 | # https://leetcode.com/problems/candy/
|
2 |
| - |
| 5 | +# |
| 6 | +# Tags: Array - Greedy |
3 | 7 |
|
4 | 8 | import timeit
|
5 | 9 | from typing import List
|
6 | 10 |
|
7 | 11 |
|
8 |
| -# Runtime: 263 ms, faster than 42.85% of Python3 online submissions for Candy. |
9 |
| -# Memory Usage: 16.9 MB, less than 37.74 % of Python3 online submissions for Candy. |
| 12 | +# Use an extra auxiliary vector of the same size as the input vector to |
| 13 | +# store the candy assigned to each child initialized to 1 for each child. |
| 14 | +# Iterate over the input array forward, for each child that has a higher |
| 15 | +# rating that the one to its left, give it one more candy that the one to |
| 16 | +# its left already has. Once we reach the end we traverse backwards, for |
| 17 | +# each child that has a higher rating than the one to its right, if its it |
| 18 | +# not already getting more candy than the one to its right is, we give it |
| 19 | +# the amount of candy that that one gets plus 1. We return the sum of |
| 20 | +# values in the assigned candy array. |
| 21 | +# |
| 22 | +# Time complexity: O(n) - We traverse over n elements twice. |
| 23 | +# Space complexity: O(n) - We store an extra vector of size n in memory. |
| 24 | +# |
| 25 | +# Runtime 141 ms Beats 73.84% |
| 26 | +# Memory 19.15 MB Beats 91.36% |
| 27 | +class TwoArrays: |
| 28 | + def candy(self, ratings): |
| 29 | + n = len(ratings) |
| 30 | + if n < 2: |
| 31 | + return n |
| 32 | + nums = [1] * n |
| 33 | + for i in range(1, n): |
| 34 | + if ratings[i] > ratings[i - 1]: |
| 35 | + nums[i] = nums[i - 1] + 1 |
| 36 | + for i in range(n - 1, 0, -1): |
| 37 | + if ratings[i - 1] > ratings[i]: |
| 38 | + nums[i - 1] = max(nums[i] + 1, nums[i - 1]) |
| 39 | + return sum(nums) |
| 40 | + |
| 41 | + |
| 42 | +# Similar solution that only uses one pass, keep track of how many |
| 43 | +# previous children's assignments depend on the current child, if it is |
| 44 | +# necessary to increase its assigned candy, increase it by one for it |
| 45 | +# and all previous children that had a higher rating. |
| 46 | +# |
| 47 | +# Time complexity: O(n) - We visit each of the n elements once and do |
| 48 | +# constant time work for each. |
| 49 | +# Space complexity: O(1) - We use constant extra memory. |
| 50 | +# |
| 51 | +# Runtime 136 ms Beats 88.46% |
| 52 | +# Memory 19.26 MB Beats 68.45% |
10 | 53 | class DescendingSequence:
|
11 | 54 | def candy(self, ratings: List[int]) -> int:
|
12 | 55 | if len(ratings) < 2:
|
@@ -47,73 +90,50 @@ def candy(self, ratings: List[int]) -> int:
|
47 | 90 | return min_candy
|
48 | 91 |
|
49 | 92 |
|
50 |
| -class TwoArrays: |
51 |
| - def candy(self, ratings): |
52 |
| - n = len(ratings) |
53 |
| - if n < 2: |
54 |
| - return n |
55 |
| - |
56 |
| - # initial state: each kid gets one candy |
57 |
| - nums = [1] * n |
58 |
| - # kids on upwards curve get candies |
59 |
| - for i in range(1, n): |
60 |
| - if ratings[i] > ratings[i-1]: |
61 |
| - nums[i] = nums[i-1] + 1 |
62 |
| - |
63 |
| - # kids on downwards curve get candies |
64 |
| - # if a kid on both up/down curves, i.e. a peak or a valley |
65 |
| - # kid gets the maximum candies among the two. |
66 |
| - # total = 0 |
67 |
| - for i in range(n-1, 0, -1): |
68 |
| - if ratings[i-1] > ratings[i]: |
69 |
| - nums[i-1] = max(nums[i]+1, nums[i-1]) |
70 |
| - # total += nums[i] |
71 |
| - |
72 |
| - # Locally it is quicker to return the sum |
73 |
| - # total += nums[0] |
74 |
| - # return total |
75 |
| - return sum(nums) |
76 |
| - |
77 |
| - |
78 | 93 | def test():
|
79 |
| - executor = [ |
80 |
| - {'executor': DescendingSequence, 'title': 'DescendingSequence', }, |
81 |
| - {'executor': TwoArrays, 'title': 'TwoArrays', }, |
| 94 | + executors = [ |
| 95 | + DescendingSequence, |
| 96 | + TwoArrays, |
82 | 97 | ]
|
83 | 98 | tests = [
|
| 99 | + [[], 0], |
| 100 | + [[15], 1], |
| 101 | + [[1, 0, 2], 5], |
| 102 | + [[1, 2, 2], 4], |
84 | 103 | [[0, 0, 0, 0], 4],
|
85 | 104 | [[0, 0, 0, -1], 5],
|
86 | 105 | [[7, 1, 0, -1], 10],
|
87 |
| - [[7, 1, 0, -1, -1], 11], |
88 |
| - [[7, 1, 0, -1, -1, 1], 13], |
89 |
| - [[7, 1, 0, -1, -1, 1, 2], 16], |
90 |
| - [[7, 1, 0, -1, -1, 1, 2, 3], 20], |
91 |
| - [[7, 1, 0, -1, -1, 1, 2, 3, 3], 21], |
92 | 106 | [[1, 2, 3, 4, 5], 15],
|
| 107 | + [[7, 1, 0, -1, -1], 11], |
93 | 108 | [[1, 2, 3, 4, 5, 4], 16],
|
| 109 | + [[1, 5, 4, 3, 2, 1], 16], |
| 110 | + [[7, 1, 0, -1, -1, 1], 13], |
94 | 111 | [[1, 2, 3, 4, 5, 4, 2], 18],
|
| 112 | + [[7, 1, 0, -1, -1, 1, 2], 16], |
95 | 113 | [[1, 2, 3, 4, 5, 4, 3, 2], 21],
|
| 114 | + [[7, 1, 0, -1, -1, 1, 2, 3], 20], |
96 | 115 | [[1, 2, 3, 4, 5, 4, 3, 2, 1], 25],
|
| 116 | + [[7, 1, 0, -1, -1, 1, 2, 3, 3], 21], |
97 | 117 | [[1, 2, 3, 4, 5, 4, 3, 2, 1, 0], 31],
|
98 | 118 | [[1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 0], 32],
|
99 | 119 | [[1, 2, 3, 4, 5, 4, 3, 2, 1, 0, 0, 1, 2, 4], 41],
|
100 |
| - [[1, 5, 4, 3, 2, 1], 16], |
101 |
| - [[1, 0, 2], 5], |
102 |
| - [[1, 2, 2], 4], |
103 |
| - [[], 0], |
104 |
| - [[15], 1], |
105 | 120 | ]
|
106 |
| - for e in executor: |
| 121 | + for executor in executors: |
107 | 122 | start = timeit.default_timer()
|
108 |
| - for _ in range(int(float('1'))): |
109 |
| - for t in tests: |
110 |
| - sol = e['executor']() |
| 123 | + for _ in range(1): |
| 124 | + for col, t in enumerate(tests): |
| 125 | + sol = executor() |
111 | 126 | result = sol.candy(t[0])
|
112 |
| - expected = t[1] |
113 |
| - assert result == expected, f'{result} != {expected}' |
| 127 | + exp = t[1] |
| 128 | + assert result == exp, ( |
| 129 | + f"\033[93m» {result} <> {exp}\033[91m for" |
| 130 | + + f" test {col} using \033[1m{executor.__name__}" |
| 131 | + ) |
114 | 132 | stop = timeit.default_timer()
|
115 | 133 | used = str(round(stop - start, 5))
|
116 |
| - print("{0:20}{1:10}{2:10}".format(e['title'], used, "seconds")) |
| 134 | + cols = "{0:20}{1:10}{2:10}" |
| 135 | + res = cols.format(executor.__name__, used, "seconds") |
| 136 | + print(f"\033[92m» {res}\033[0m") |
117 | 137 |
|
118 | 138 |
|
119 | 139 | test()
|
0 commit comments