Skip to content

Commit 66f332c

Browse files
committed
[chore] add markdown versions of DP notebooks
1 parent 2d4e155 commit 66f332c

13 files changed

+904
-0
lines changed

dynamic-programming/disk_stacking.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
### Disk stacking
2+
An array's element represents a disk. Each element has `[length, width, height]`
3+
Write a function that will stack the disks and build a tower with the greatest height, such that each disk has strictly lower dimensions than those below it.
4+
5+
Sample input
6+
```
7+
array = [[2, 1, 2], [3, 2, 3], [2, 2, 8], [2, 3, 4], [1, 3, 1], [4, 4, 5]]
8+
```
9+
10+
Sample output:
11+
```
12+
[[4, 4, 5], [3, 2, 3], [2, 1, 2]]
13+
14+
The tower looks something like this
15+
16+
[2, 1, 2]
17+
[ 3, 2, 3 ]
18+
[4, 4, 5]
19+
```
20+
21+
22+
23+
```python
24+
def diskStacking(disks):
25+
"""O(n) space, O(n^2) time"""
26+
# sort based on height
27+
disks.sort(key=lambda disk: disk[2])
28+
diskHeights = [disk[2] for disk in disks]
29+
sequences = [None for disk in disks]
30+
31+
# maxHeightIndex
32+
maxHeightIndex = 0
33+
34+
for i in range(1, len(disks)):
35+
currentDisk = disks[i]
36+
for j in range(0, i):
37+
otherDisk = disks[j]
38+
# validate dimensions
39+
if areValidDimensions(otherDisk, currentDisk):
40+
if diskHeights[i] <= currentDisk[2] + diskHeights[j]:
41+
diskHeights[i] = currentDisk[2] + diskHeights[j]
42+
sequences[i] = j
43+
# update maxHeightIndex: which will help us backtrack to find the disks involved.
44+
if diskHeights[i] >= diskHeights[maxHeightIndex]:
45+
maxHeightIndex = i
46+
return buildSequence(disks, sequences, maxHeightIndex)
47+
48+
def buildSequence(array, sequences, currentIdx):
49+
results = []
50+
while currentIdx is not None:
51+
results.append(disks[currentIdx])
52+
currentIdx = sequences[currentIdx]
53+
return results
54+
55+
def areValidDimensions(o, c):
56+
return o[0] < c[0] and o[1] < c[1] and o[2] < c[2]
57+
58+
```
59+
60+
61+
```python
62+
disks = [[2, 1, 2], [3, 2, 3], [2, 2, 8], [2, 3, 4], [1, 3, 1], [4, 4, 5]]
63+
diskStacking(disks)
64+
```
65+
66+
67+
68+
69+
[[4, 4, 5], [3, 2, 3], [2, 1, 2]]
70+
71+
72+
73+
74+
```python
75+
76+
```

dynamic-programming/fibonacci.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
```python
2+
def fibonacci(n):
3+
dp = [0, 1]
4+
for i in range(2, n + 1):
5+
dp.append(dp[i - 1] + dp[i - 2])
6+
return dp[n]
7+
```
8+
9+
10+
```python
11+
def fibo(n, memoize={1:0,2:1}):
12+
if n < 2:
13+
return n
14+
15+
memoize[n] = fibo(n - 1, memoize) + fibo(n - 2, memoize)
16+
return memoize[n]
17+
```
18+
19+
20+
```python
21+
fibo(5)
22+
```
23+
24+
25+
26+
27+
5
28+
29+
30+
31+
32+
```python
33+
fibonacci(6)
34+
```
35+
36+
37+
38+
39+
8
40+
41+
42+
43+
44+
```python
45+
46+
```
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
### Problem
2+
You are given an array of length N, where each element i represents the number of ways we can produce i units of change. For example, [1, 0, 1, 1, 2] shows that there is only one way to make [0, 2, or 3] units, and 2 ways of making 4 units.
3+
4+
Given such an array, determine the denominations that must be in use. In the case above, there must be coins with value 2, 3, and 4.
5+
6+
### Approach
7+
8+
There are two situation that will make the value at that index i be incremented:
9+
1. Coin `i` is one of the denominations
10+
2. Another coin `j` is one of the denominations and the value of array[i - j] is also non-zero
11+
12+
For each index:
13+
- Check the lower denominations j that are known to be part of the solution.
14+
- Each time we find `i - j` to be non-zero, we have encountered one of the ways of getting to element `i`, so we decrement the value at that index by 1.
15+
- If after going through all coins and the value at that index is still positive, we know that we must include `i` as part of the solution
16+
17+
We must take note not to double count. For example, when `i == 7` and [3, 4] are in our solution set, that is one way of producing 7.
18+
When two coins sum up to an index, only the lower one cause us to decrement the value at that index.
19+
20+
21+
22+
23+
```python
24+
def find_denominations(array):
25+
coins = set()
26+
# start from index 1, and start counting from 1 (not zero-based index)
27+
for i, val in enumerate(array[1:], 1):
28+
if val > 0:
29+
for j in coins:
30+
if array[i - j] > 0 and (i - j not in coins or i - j <= j):
31+
val -= 1
32+
if val > 0:
33+
coins.add(i)
34+
return coins
35+
```
36+
37+
38+
```python
39+
find_denominations([1, 0, 1, 1, 2])
40+
```
41+
42+
43+
44+
45+
{2, 3, 4}
46+
47+
48+
49+
The time complexity of this algorithm is O(M * N), where M is the number of coins in our solution and N is the length of our input.
50+
51+
The space complexity will be O(M), since we require extra space to store the set of solution coins.
52+
53+
54+
```python
55+
56+
```
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
### Problem
2+
Given an array of integers, find the largest possible sum of contiguous subarray within the given array.
3+
4+
5+
```python
6+
## solution
7+
def kadanes_algorithm(array):
8+
"""Complexity: O(n) time | O(1) space"""
9+
10+
local_max = global_max = array[0]
11+
for i in range(1, len(array)):
12+
# the local maximum for an index is always => max(array[i], local_max of array[i - 1])
13+
local_max = max(array[i], array[i] + local_max)
14+
global_max = max(global_max, local_max)
15+
return global_max
16+
```
17+
18+
19+
```python
20+
array = [-3, 4, -1, 2, 1, -5, 4, -12, 3, -7]
21+
kadanes_algorithm(array)
22+
```
23+
24+
25+
26+
27+
6
28+
29+
30+
31+
32+
```python
33+
## unit tests to validate solution
34+
import unittest
35+
36+
class KadenesTestCase(unittest.TestCase):
37+
def test_case_1(self):
38+
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
39+
expected_sum = 55
40+
self.assertEqual(kadanes_algorithm(array), expected_sum)
41+
42+
def test_case_2(self):
43+
array = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
44+
expected_sum = 6
45+
self.assertEqual(kadanes_algorithm(array), expected_sum)
46+
47+
if __name__ == "__main__":
48+
unittest.main(argv=['first-arg-is-ignored'], exit=False)
49+
```
50+
51+
52+
```python
53+
kadanes_algorithm([1, -1, 2, 3, -6])
54+
```
55+
56+
57+
58+
59+
5
60+
61+
62+
63+
64+
```python
65+
66+
```

dynamic-programming/knapsack.md

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
## Knapsack Problem
2+
You are given an array of arrays. Each subarray in this array contains two integer elements: the first represents an item value, the second an item's weight.
3+
4+
You are also given an integer representing the maximum capacity of the knapsack that you have.
5+
6+
Your goal is to fit items that will collectively fit within the knapsack's capacity while maximizing on their combined value.
7+
8+
Write a function that returns the maximum combined value of the items you'd pick, as well as an array of the item indices picked.
9+
10+
Sample Input: [[1,2],[4,3],[5,6],[6,7]], 10
11+
Sample Output: 10, [1, 3]
12+
13+
14+
15+
16+
```python
17+
def knapsack(items, capacity):
18+
"""O(nc) time | O(nc) space, where n == number of items, c == capacity"""
19+
knapsack_values = [[0 for col in range(capacity + 1)] for row in range(len(items) + 1)]
20+
21+
for row in range(1, len(items) + 1):
22+
value = items[row - 1][0]
23+
weight = items[row - 1][1]
24+
for col in range(capacity + 1):
25+
if weight > col: # col here represents a given capacity
26+
knapsack_values[row][col] = knapsack_values[row - 1][col]
27+
else:
28+
knapsack_values[row][col] = max(
29+
knapsack_values[row - 1][col],
30+
knapsack_values[row - 1][col - weight] + value
31+
)
32+
33+
return [knapsack_values[-1][-1], backtrack_items(knapsack_values, items)]
34+
35+
def backtrack_items(values, items):
36+
"""
37+
Backtracks from the bottom right of the 2d array, finding all the items that were put in the knapsack.
38+
"""
39+
results = []
40+
row = len(values) - 1
41+
col = len(values[0]) - 1
42+
43+
while row > 0:
44+
if values[row][col] == values[row - 1][col]:
45+
row -= 1
46+
else:
47+
results.append(row - 1)
48+
col -= items[row - 1][1]
49+
row -= 1
50+
return list(reversed(results))
51+
```
52+
53+
54+
```python
55+
# test it out
56+
capacity = 10
57+
items = [[1, 3], [4, 3], [5, 6], [6, 7]]
58+
59+
knapsack(items, capacity)
60+
```
61+
62+
63+
64+
65+
[10, [1, 3]]
66+
67+
68+
69+
### Unit Tests
70+
71+
72+
```python
73+
# unit tests
74+
import unittest
75+
76+
class KnapsackTestCase(unittest.TestCase):
77+
def test_case_1(self):
78+
capacity = 10
79+
items = [[1, 3], [4, 3], [5, 6], [6, 7]]
80+
expected = [10, [1, 3]]
81+
self.assertEqual(knapsack(items, capacity), expected)
82+
83+
def test_case_when_capacity_is_zero(self):
84+
capacity = 0
85+
items = [[1, 3], [4, 3], [5, 6], [6, 7]]
86+
expected = [0, []]
87+
self.assertEqual(knapsack(items, capacity), expected)
88+
89+
90+
if __name__ == "__main__":
91+
unittest.main(argv=[""], exit=False)
92+
```

0 commit comments

Comments
 (0)