Skip to content

Commit 3c5ac87

Browse files
authored
Merge pull request #95 from BrianLusina/feat/algorithms-non-constructible-change
feat(algorithms) non constructible change
2 parents ced3110 + 8549713 commit 3c5ac87

File tree

4 files changed

+155
-0
lines changed

4 files changed

+155
-0
lines changed

DIRECTORY.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
* [Test Intersection Two](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/arrays/intersection/test_intersection_two.py)
1010
* Majority Element
1111
* [Test Majority Element](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/arrays/majority_element/test_majority_element.py)
12+
* Non Constructible Change
13+
* [Test Non Constructible Change](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/arrays/non_constructible_change/test_non_constructible_change.py)
1214
* Optimal Task Assignment
1315
* [Test Optimal Task Assignment](https://github.com/BrianLusina/PythonSnips/blob/master/algorithms/arrays/optimal_task_assignment/test_optimal_task_assignment.py)
1416
* Remove Duplicates
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Non-Constructible Change
2+
3+
Given an array of positive integers representing the values of coins in your
4+
possession, write a function that returns the minimum amount of change (the
5+
minimum sum of money) that you cannot create. The given coins can have
6+
any positive integer value and aren't necessarily unique (i.e., you can have
7+
multiple coins of the same value).
8+
9+
10+
Sample Input:
11+
12+
```text
13+
coins = [5,7,1,1,2,3,22]
14+
```
15+
16+
Sample output:
17+
18+
```text
19+
20
20+
```
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
from typing import List
2+
3+
4+
def non_constructible_change(coins: List[int]) -> int:
5+
"""
6+
Return the smallest amount of change that cannot be created from the given coins.
7+
Greedy approach: track the maximum constructible change 'current_change_created'.
8+
If the next coin is greater than current_change_created + 1, we've found the gap.
9+
10+
Examples:
11+
>>> non_constructible_change([5, 7, 1, 1, 2, 3, 22])
12+
20
13+
>>> non_constructible_change([])
14+
1
15+
>>> non_constructible_change([1, 1, 1, 1, 1])
16+
6
17+
"""
18+
# Do not mutate the caller's input; iterate over a sorted copy.
19+
sorted_coins = sorted(coins)
20+
21+
current_change_created = 0
22+
23+
for coin in sorted_coins:
24+
if coin > current_change_created + 1:
25+
return current_change_created + 1
26+
current_change_created += coin
27+
28+
return current_change_created + 1
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import unittest
2+
from . import non_constructible_change
3+
4+
5+
class NonConstructibleChangeTestCase(unittest.TestCase):
6+
def test_1(self):
7+
"""should return 20 for input of [5, 7, 1, 1, 2, 3, 22]"""
8+
coins = [5, 7, 1, 1, 2, 3, 22]
9+
expected = 20
10+
actual = non_constructible_change(coins)
11+
self.assertEqual(actual, expected)
12+
13+
def test_2(self):
14+
"""should return 6 for input of [1, 1, 1, 1, 1]"""
15+
coins = [1, 1, 1, 1, 1]
16+
expected = 6
17+
actual = non_constructible_change(coins)
18+
self.assertEqual(actual, expected)
19+
20+
def test_3(self):
21+
"""should return 55 for input of [1, 5, 1, 1, 1, 10, 15, 20, 100]"""
22+
coins = [1, 5, 1, 1, 1, 10, 15, 20, 100]
23+
expected = 55
24+
actual = non_constructible_change(coins)
25+
self.assertEqual(actual, expected)
26+
27+
def test_4(self):
28+
"""should return 3 for input of [6, 4, 5, 1, 1, 8, 9]"""
29+
coins = [6, 4, 5, 1, 1, 8, 9]
30+
expected = 3
31+
actual = non_constructible_change(coins)
32+
self.assertEqual(actual, expected)
33+
34+
def test_5(self):
35+
"""should return 1 for input of []"""
36+
coins = []
37+
expected = 1
38+
actual = non_constructible_change(coins)
39+
self.assertEqual(actual, expected)
40+
41+
def test_6(self):
42+
"""should return 1 for input of [87]"""
43+
coins = [87]
44+
expected = 1
45+
actual = non_constructible_change(coins)
46+
self.assertEqual(actual, expected)
47+
48+
def test_7(self):
49+
"""should return 32 for input of [5, 6, 1, 1, 2, 3, 4, 9]"""
50+
coins = [5, 6, 1, 1, 2, 3, 4, 9]
51+
expected = 32
52+
actual = non_constructible_change(coins)
53+
self.assertEqual(actual, expected)
54+
55+
def test_8(self):
56+
"""should return 19 for input of [5, 6, 1, 1, 2, 3, 43]"""
57+
coins = [5, 6, 1, 1, 2, 3, 43]
58+
expected = 19
59+
actual = non_constructible_change(coins)
60+
self.assertEqual(actual, expected)
61+
62+
def test_9(self):
63+
"""should return 3 for input of [1, 1]"""
64+
coins = [1, 1]
65+
expected = 3
66+
actual = non_constructible_change(coins)
67+
self.assertEqual(actual, expected)
68+
69+
def test_10(self):
70+
"""should return 1 for input of [2]"""
71+
coins = [2]
72+
expected = 1
73+
actual = non_constructible_change(coins)
74+
self.assertEqual(actual, expected)
75+
76+
def test_11(self):
77+
"""should return 2 for input of [1]"""
78+
coins = [1]
79+
expected = 2
80+
actual = non_constructible_change(coins)
81+
self.assertEqual(actual, expected)
82+
83+
def test_12(self):
84+
"""should return 87 for input of [109, 2000, 8765, 19, 18, 17, 16, 8, 1, 1, 2, 4]"""
85+
coins = [109, 2000, 8765, 19, 18, 17, 16, 8, 1, 1, 2, 4]
86+
expected = 87
87+
actual = non_constructible_change(coins)
88+
self.assertEqual(actual, expected)
89+
90+
def test_13(self):
91+
"""should return 29 for input of [1, 2, 3, 4, 5, 6, 7]"""
92+
coins = [1, 2, 3, 4, 5, 6, 7]
93+
expected = 29
94+
actual = non_constructible_change(coins)
95+
self.assertEqual(actual, expected)
96+
97+
def test_input_not_mutated(self):
98+
"""should not mutate the input coins list"""
99+
coins = [5, 7, 1, 1, 2, 3, 22]
100+
snapshot = coins[:]
101+
_ = non_constructible_change(coins)
102+
self.assertEqual(coins, snapshot)
103+
104+
if __name__ == '__main__':
105+
unittest.main()

0 commit comments

Comments
 (0)