-
Notifications
You must be signed in to change notification settings - Fork 164
/
05_PassingCars.py
160 lines (122 loc) · 4.99 KB
/
05_PassingCars.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
"""
# Passing Cars
Count the number of passing cars on the road.
A non-empty array A consisting of N integers is given.
The consecutive elements of array A represent consecutive cars on a road.
Array A contains only 0s and/or 1s:
0 represents a car traveling east,
1 represents a car traveling west.
The goal is to count passing cars. We say that a pair of cars (P, Q),
where 0 ≤ P < Q < N, is passing when P is traveling to the east
and Q is traveling to the west.
For example, consider array A such that:
A[0] = 0
A[1] = 1
A[2] = 0
A[3] = 1
A[4] = 1
We have five pairs of passing cars: (0, 1), (0, 3), (0, 4), (2, 3), (2, 4).
Write a function:
def solution(A)
that, given a non-empty array A of N integers, returns the number of pairs of passing cars.
The function should return -1 if the number of pairs of passing cars exceeds 1,000,000,000.
For example, given:
A[0] = 0
A[1] = 1
A[2] = 0
A[3] = 1
A[4] = 1
the function should return 5, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer that can have one of the following values: 0, 1.
Copyright 2009–2022 by Codility Limited. All Rights Reserved.
Unauthorized copying, publication or disclosure prohibited.
"""
import unittest
import random
MAX_PAIRS = int(1e9)
def solution(A):
"""Count the number of passing cars on the road.
:param A: list[int] A sequence of cars traveling east (0) or west (1).
:return: [int] A count of the pairs of cars passing, or -1.
NB: A car travelling east only 'passes' the cars travelling west, which are
after it in the series.
Another way to think of it is:
"For every 0, how many 1's does it pass through to get to the right end
of the array?"
Solution A: O(log(N))
From the left, we grab every "0" and move it right, counting the
number of "1"s it passes, then sum all those counts together.
This passes every element in the array over every other element
to its right in the array.
Solution B: O(N)
From the left, we count every '0'. When we encounter a '1' we add the
current count, all the cars going east that will pass this one going west,
to the total: O(N).
Lesson:
When passing over a dataset think about how accumulating metadata about that
data can reduce the need to see the data again.
In this example, we accumulate the count of cars going east so that, when
we encounter a car going west, we can apply the metadata and never look back.
"""
east = passes = 0
for direction in A:
if direction == 0: # Going East.
east += 1
else: # Going West.
passes += east
if passes > MAX_PAIRS: # They do test for this!
return -1
return passes
class TestExercise(unittest.TestCase):
"""
example: example test
single: single element
double: two elements
simple: simple test
small_random: random, length = 100
small_random2: random, length = 1000
medium_random: random, length = ~10,000
large_random: random, length = ~100,000
large_big_answer: 0..01..1, length = ~100,000
large_alternate: 0101..01, length = ~100,000
large_extreme: large test with all 1s/0s, length = ~100,000
"""
def test_example(self):
self.assertEqual(solution([0, 1, 0, 1, 1]), 5)
def test_minimal(self):
self.assertEqual(solution([0]), 0)
self.assertEqual(solution([1]), 0)
self.assertEqual(solution([0, 0]), 0)
self.assertEqual(solution([1, 1]), 0)
self.assertEqual(solution([0, 1]), 1)
self.assertEqual(solution([1, 0]), 0)
def test_three(self):
self.assertEqual(solution([0, 0, 0]), 0)
self.assertEqual(solution([0, 0, 1]), 2)
self.assertEqual(solution([0, 1, 0]), 1)
self.assertEqual(solution([0, 1, 1]), 2)
self.assertEqual(solution([1, 0, 0]), 0)
self.assertEqual(solution([1, 0, 1]), 1)
self.assertEqual(solution([1, 1, 0]), 0)
self.assertEqual(solution([1, 1, 1]), 0)
def test_four(self):
self.assertEqual(solution([0, 0, 0, 0]), 0)
self.assertEqual(solution([0, 0, 0, 1]), 3)
self.assertEqual(solution([0, 0, 1, 1]), 4)
self.assertEqual(solution([0, 1, 0, 0]), 1)
self.assertEqual(solution([0, 1, 0, 1]), 3)
self.assertEqual(solution([0, 1, 1, 1]), 3)
self.assertEqual(solution([1, 0, 0, 0]), 0)
self.assertEqual(solution([1, 0, 0, 1]), 2)
self.assertEqual(solution([1, 0, 1, 0]), 1)
self.assertEqual(solution([1, 0, 1, 1]), 2)
self.assertEqual(solution([1, 1, 0, 0]), 0)
self.assertEqual(solution([1, 1, 0, 1]), 1)
self.assertEqual(solution([1, 1, 1, 0]), 0)
self.assertEqual(solution([1, 1, 1, 1]), 0)
def test_extreme(self):
self.assertEqual(-1, solution([random.randint(0, 1) for _ in range(int(1e6))]))
if __name__ == "__main__":
unittest.main()