-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
collecting-chocolates.py
95 lines (85 loc) · 2.83 KB
/
collecting-chocolates.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# Time: O(n)
# Space: O(n)
# mono stack, difference array, prefix sum
class Solution(object):
def minCost(self, nums, x):
"""
:type nums: List[int]
:type x: int
:rtype: int
"""
def accumulate(a):
for i in xrange(len(a)-1):
a[i+1] += a[i]
return a
i = min(xrange(len(nums)), key=lambda x: nums[x])
nums = nums[i:]+nums[:i]
left, right = [-1]*len(nums), [len(nums)]*len(nums)
stk = []
for i in xrange(len(nums)):
while stk and nums[stk[-1]] > nums[i]:
right[stk.pop()] = i
if stk:
left[i] = stk[-1]
stk.append(i)
diff2 = [0]*(len(nums)+1)
diff2[0] = (+1)*sum(nums) # diff1[k] has sum((+1)*nums[i] for i in xrange(len(nums))) for k >= 0
diff2[1] = x # diff1[k] has x for k >= 1
diff2[-1] += (-1)*nums[0] # diff1[len(nums)] has 0*nums[0]
for i in xrange(1, len(nums)):
l, r = i-left[i], right[i]-i
diff2[min(l, r)] += (-1)*nums[i] # diff1[k] has 0*nums[i] for min(l, r) <= k < max(l, r)
diff2[max(l, r)] += (-1)*nums[i] # diff1[k] has (-1)*nums[i] for max(l, r) <= k < l+r
diff2[l+r] += (+1)*nums[i] # diff1[k] has 0*nums[i] to for k >= l+r
return min(accumulate(accumulate(diff2)))
# Time: O(nlogn)
# Space: O(n)
import collections
# binary search, mono deque
class Solution2(object):
def minCost(self, nums, x):
"""
:type nums: List[int]
:type x: int
:rtype: int
"""
def cost(k):
w = k+1
result = x*k
dq = collections.deque()
for i in xrange(len(nums)+w-1):
if dq and i-dq[0] == w:
dq.popleft()
while dq and nums[dq[-1]%len(nums)] >= nums[i%len(nums)]:
dq.pop()
dq.append(i)
if i >= w-1:
result += nums[dq[0]%len(nums)]
return result
def check(x):
return cost(x) <= cost(x+1)
left, right = 0, len(nums)
while left <= right:
mid = left + (right-left)//2
if check(mid):
right = mid-1
else:
left = mid+1
return cost(left)
# Time: O(n^2)
# Space: O(n)
# brute force
class Solution3(object):
def minCost(self, nums, x):
"""
:type nums: List[int]
:type x: int
:rtype: int
"""
result = [x*k for k in xrange(len(nums)+1)]
for i in xrange(len(nums)):
curr = nums[i]
for k in xrange(len(result)):
curr = min(curr, nums[(i+k)%len(nums)])
result[k] += curr
return min(result)