Skip to content

Commit 4076784

Browse files
author
Mauricio Klein
committed
Add solution for challenge #48
1 parent f835a78 commit 4076784

File tree

6 files changed

+108
-0
lines changed

6 files changed

+108
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,4 @@
4747
- [x] [Challenge 45: Occurrences of a number in a sorted array](challenge-45/)
4848
- [x] [Challenge 46: Sudoku solver](challenge-46/)
4949
- [x] [Challenge 47: Closest coin](challenge-47/)
50+
- [x] [Challenge 48: Median of window](challenge-48/)

challenge-48/Makefile

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
test:
2+
python test_*.py
3+
4+
.PHONY: test

challenge-48/README.md

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Median of window
2+
3+
This problem was asked by Microsoft.
4+
5+
## Description
6+
7+
Given an array of numbers "arr" and a window of size "k", return an array with the median of each window of size "k" starting from the left and moving right by one position each time.
8+
9+
Recall that the median of an even-sized list is the average of the two middle numbers.
10+
11+
## Example
12+
```
13+
Input:
14+
arr: [-1, 5, 13, 8, 2, 3, 3, 1]
15+
16+
Output:
17+
[5, 8, 8, 3, 3, 3]
18+
# 5 <- median of [-1, 5, 13]
19+
# 8 <- median of [5, 13, 8]
20+
# 8 <- median of [13, 8, 2]
21+
# 3 <- median of [8, 2, 3]
22+
# 3 <- median of [2, 3, 3]
23+
# 3 <- median of [3, 3, 1]
24+
```

challenge-48/__init__.py

Whitespace-only changes.

challenge-48/solver.py

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import bisect
2+
3+
#
4+
# Brute force solution:
5+
# For each window with "k" elements, sort the window and return the median.
6+
# Time complexity: O(n*klog(k))
7+
# Space complexity: O(n) (for the output array)
8+
#
9+
10+
#
11+
# Optimized solution:
12+
# Initialize the window with the "k" first elements using bisect insert to place the element while keeping the
13+
# window sorted. For every new window, remove the oldest element and add the new one, using bisect insert.
14+
# Return the median of each window as usual
15+
# Time complexity: O(n*k)
16+
# Space complexity: O(n) (for the output array)
17+
18+
#
19+
# Time complexity: O(n*k) (n = number of elements in the array)
20+
# Space complexity: O(n) (for the output buffer)
21+
#
22+
def subarr_mean(arr, k):
23+
# Populate the buffer with the first "k" elements of the array,
24+
# adding them in order, to keep the array sorted: O(k)
25+
buffer = []
26+
for i in range(0, k):
27+
bisect.insort(buffer, arr[i])
28+
29+
oldest = arr[0]
30+
output = [median(buffer, k)]
31+
32+
for i in range(k, len(arr)):
33+
# Remove the oldest value: O(k)
34+
buffer.remove(oldest)
35+
36+
# Insert the new value on the right place, in
37+
# order to keep the buffer sorted: O(k)
38+
bisect.insort(buffer, arr[i])
39+
40+
# Add the median to the output array: O(1)
41+
output.append(median(buffer, k))
42+
43+
# Update the oldest value: O(1)
44+
oldest = arr[i - k + 1]
45+
46+
return output
47+
48+
#
49+
# Time complexity: O(1)
50+
# Space complexity: O(1)
51+
#
52+
def median(subarr, k):
53+
"""
54+
Return the median of the subarray based on the value ok "k"
55+
"""
56+
even_k = (k % 2 == 0)
57+
58+
if even_k:
59+
right = k / 2
60+
left = right - 1
61+
62+
return (subarr[left] + subarr[right]) / 2
63+
else:
64+
id = k // 2
65+
66+
return subarr[id]
67+

challenge-48/test_solver.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import unittest
2+
from solver import subarr_mean
3+
4+
class TestSolver(unittest.TestCase):
5+
def test_closest_coin(self):
6+
self.assertEqual(subarr_mean([-1, 5, 13, 8, 2, 3, 3, 1], k=3), [5, 8, 8, 3, 3, 3])
7+
self.assertEqual(subarr_mean([-1, 5, 13, 8, 2, 3, 3, 1], k=4), [6, 6, 5, 3, 2 ])
8+
self.assertEqual(subarr_mean([1, 2, 3, 4 ], k=1), [1, 2, 3, 4 ])
9+
self.assertEqual(subarr_mean([1, 50, 10, 20 ], k=4), [15 ])
10+
11+
if __name__ == "__main__":
12+
unittest.main()

0 commit comments

Comments
 (0)