forked from rtheunissen/foobar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmad_science_quarterly.py
executable file
·122 lines (91 loc) · 4.2 KB
/
mad_science_quarterly.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""
Mad science quarterly
=====================
The deadline for submitting papers to the Mad Science Quarterly is approaching.
Professor Boolean's topic: On the Rate of Growth of Zombie Rabbits.
In the lab, Boolean's minions recorded the net growth of the number of zombits
for each day, which is the number of births minus the number of deaths (yes,
zombits do die). He realized that if these figures were to be added up over
time, it would seem like the zombits multiplied very quickly.
Then everyone shall be convinced of his mad genius! He would proudly display
these figures in his paper. Since some of the figures may be negative,
and larger numbers are more convincing, Professor Boolean will choose which
figures to show so that the sum is maximized. However, he must show a sequence
of consecutive figures without omitting the unfavorable ones - Professor Boolean
also needs to be scientific, you see.
Unfortunately, the Mad Science Quarterly limits how much data can be
shown - it is, after all, Mad. This means the mad doctor can display no more
than a certain number of figures.
Write a function answer(L, k) which returns the maximum sum Professor Boolean
can obtain by choosing some consecutive figures from his data. L will be a list
of integers representing his data, the daily net growth of the number of zombits
over a period of time. k will be the maximum number of figures he can display.
Each element of L will have absolute value no greater than 100. L will contain
at least 2 and no more than 7000 elements, and at least one element will be
positive. k will be an integer, at least 3 and no greater than the length of L.
"""
class Accumulator:
"""
Provides constant time operations for add, len and sum,
but doesn't directly support access or removal.
"""
def __init__(self, initial = None):
if initial is not None:
self._values = [initial]
self._sum = initial
else:
self._values = []
self._sum = 0
def add(self, value):
self._values.append(value)
self._sum += value
def extend(self, other):
self._values.extend(other._values)
self._sum += other.sum()
def sum(self):
return self._sum
def __len__(self):
return len(self._values)
class ZombitGrowthMaximizer:
@staticmethod
def calculate(numbers, limit):
"""
Calculates the maximum sum of a limited-length subsequence.
This is also known as the sliding window minimum problem.
"""
maximum = None
# step through each value from back to front
for i in xrange(len(numbers) - 1, -1, -1):
if numbers[i] < 0:
# check max to catch the case when all numbers are negative
maximum = max(maximum, numbers[i])
continue
# an accumulator to keep track of the current psotitive sum
positives = Accumulator()
# initialize the index for the secondary loop
j = i
while j >= 0 and len(positives) < limit:
if numbers[j] >= 0:
# a positive value can be added to the accumulator
positives.add(numbers[j])
# update the maximum if the accumulator is greater
maximum = max(maximum, positives.sum())
else:
# an accumulator for collecting negative values
negatives = Accumulator(numbers[j])
# accumulate any successive negative values
while j - 1 >= 0 and numbers[j - 1] < 0:
negatives.add(numbers[j - 1])
j -= 1
# break if too many negatives have been accumulated
if len(positives) + len(negatives) == limit:
break
if positives.sum() + negatives.sum() > 0:
positives.extend(negatives)
else:
# too many negatives or the negative sum was too large.
break
j -= 1
return maximum
def answer(L, k):
return ZombitGrowthMaximizer.calculate(L, k)