forked from gitgik/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[chore] add markdown versions of DP notebooks
- Loading branch information
Showing
13 changed files
with
904 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
### Disk stacking | ||
An array's element represents a disk. Each element has `[length, width, height]` | ||
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. | ||
|
||
Sample input | ||
``` | ||
array = [[2, 1, 2], [3, 2, 3], [2, 2, 8], [2, 3, 4], [1, 3, 1], [4, 4, 5]] | ||
``` | ||
|
||
Sample output: | ||
``` | ||
[[4, 4, 5], [3, 2, 3], [2, 1, 2]] | ||
The tower looks something like this | ||
[2, 1, 2] | ||
[ 3, 2, 3 ] | ||
[4, 4, 5] | ||
``` | ||
|
||
|
||
|
||
```python | ||
def diskStacking(disks): | ||
"""O(n) space, O(n^2) time""" | ||
# sort based on height | ||
disks.sort(key=lambda disk: disk[2]) | ||
diskHeights = [disk[2] for disk in disks] | ||
sequences = [None for disk in disks] | ||
|
||
# maxHeightIndex | ||
maxHeightIndex = 0 | ||
|
||
for i in range(1, len(disks)): | ||
currentDisk = disks[i] | ||
for j in range(0, i): | ||
otherDisk = disks[j] | ||
# validate dimensions | ||
if areValidDimensions(otherDisk, currentDisk): | ||
if diskHeights[i] <= currentDisk[2] + diskHeights[j]: | ||
diskHeights[i] = currentDisk[2] + diskHeights[j] | ||
sequences[i] = j | ||
# update maxHeightIndex: which will help us backtrack to find the disks involved. | ||
if diskHeights[i] >= diskHeights[maxHeightIndex]: | ||
maxHeightIndex = i | ||
return buildSequence(disks, sequences, maxHeightIndex) | ||
|
||
def buildSequence(array, sequences, currentIdx): | ||
results = [] | ||
while currentIdx is not None: | ||
results.append(disks[currentIdx]) | ||
currentIdx = sequences[currentIdx] | ||
return results | ||
|
||
def areValidDimensions(o, c): | ||
return o[0] < c[0] and o[1] < c[1] and o[2] < c[2] | ||
|
||
``` | ||
|
||
|
||
```python | ||
disks = [[2, 1, 2], [3, 2, 3], [2, 2, 8], [2, 3, 4], [1, 3, 1], [4, 4, 5]] | ||
diskStacking(disks) | ||
``` | ||
|
||
|
||
|
||
|
||
[[4, 4, 5], [3, 2, 3], [2, 1, 2]] | ||
|
||
|
||
|
||
|
||
```python | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
```python | ||
def fibonacci(n): | ||
dp = [0, 1] | ||
for i in range(2, n + 1): | ||
dp.append(dp[i - 1] + dp[i - 2]) | ||
return dp[n] | ||
``` | ||
|
||
|
||
```python | ||
def fibo(n, memoize={1:0,2:1}): | ||
if n < 2: | ||
return n | ||
|
||
memoize[n] = fibo(n - 1, memoize) + fibo(n - 2, memoize) | ||
return memoize[n] | ||
``` | ||
|
||
|
||
```python | ||
fibo(5) | ||
``` | ||
|
||
|
||
|
||
|
||
5 | ||
|
||
|
||
|
||
|
||
```python | ||
fibonacci(6) | ||
``` | ||
|
||
|
||
|
||
|
||
8 | ||
|
||
|
||
|
||
|
||
```python | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
### Problem | ||
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. | ||
|
||
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. | ||
|
||
### Approach | ||
|
||
There are two situation that will make the value at that index i be incremented: | ||
1. Coin `i` is one of the denominations | ||
2. Another coin `j` is one of the denominations and the value of array[i - j] is also non-zero | ||
|
||
For each index: | ||
- Check the lower denominations j that are known to be part of the solution. | ||
- 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. | ||
- 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 | ||
|
||
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. | ||
When two coins sum up to an index, only the lower one cause us to decrement the value at that index. | ||
|
||
|
||
|
||
|
||
```python | ||
def find_denominations(array): | ||
coins = set() | ||
# start from index 1, and start counting from 1 (not zero-based index) | ||
for i, val in enumerate(array[1:], 1): | ||
if val > 0: | ||
for j in coins: | ||
if array[i - j] > 0 and (i - j not in coins or i - j <= j): | ||
val -= 1 | ||
if val > 0: | ||
coins.add(i) | ||
return coins | ||
``` | ||
|
||
|
||
```python | ||
find_denominations([1, 0, 1, 1, 2]) | ||
``` | ||
|
||
|
||
|
||
|
||
{2, 3, 4} | ||
|
||
|
||
|
||
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. | ||
|
||
The space complexity will be O(M), since we require extra space to store the set of solution coins. | ||
|
||
|
||
```python | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
### Problem | ||
Given an array of integers, find the largest possible sum of contiguous subarray within the given array. | ||
|
||
|
||
```python | ||
## solution | ||
def kadanes_algorithm(array): | ||
"""Complexity: O(n) time | O(1) space""" | ||
|
||
local_max = global_max = array[0] | ||
for i in range(1, len(array)): | ||
# the local maximum for an index is always => max(array[i], local_max of array[i - 1]) | ||
local_max = max(array[i], array[i] + local_max) | ||
global_max = max(global_max, local_max) | ||
return global_max | ||
``` | ||
|
||
|
||
```python | ||
array = [-3, 4, -1, 2, 1, -5, 4, -12, 3, -7] | ||
kadanes_algorithm(array) | ||
``` | ||
|
||
|
||
|
||
|
||
6 | ||
|
||
|
||
|
||
|
||
```python | ||
## unit tests to validate solution | ||
import unittest | ||
|
||
class KadenesTestCase(unittest.TestCase): | ||
def test_case_1(self): | ||
array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | ||
expected_sum = 55 | ||
self.assertEqual(kadanes_algorithm(array), expected_sum) | ||
|
||
def test_case_2(self): | ||
array = [-2, 1, -3, 4, -1, 2, 1, -5, 4] | ||
expected_sum = 6 | ||
self.assertEqual(kadanes_algorithm(array), expected_sum) | ||
|
||
if __name__ == "__main__": | ||
unittest.main(argv=['first-arg-is-ignored'], exit=False) | ||
``` | ||
|
||
|
||
```python | ||
kadanes_algorithm([1, -1, 2, 3, -6]) | ||
``` | ||
|
||
|
||
|
||
|
||
5 | ||
|
||
|
||
|
||
|
||
```python | ||
|
||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
## Knapsack Problem | ||
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. | ||
|
||
You are also given an integer representing the maximum capacity of the knapsack that you have. | ||
|
||
Your goal is to fit items that will collectively fit within the knapsack's capacity while maximizing on their combined value. | ||
|
||
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. | ||
|
||
Sample Input: [[1,2],[4,3],[5,6],[6,7]], 10 | ||
Sample Output: 10, [1, 3] | ||
|
||
|
||
|
||
|
||
```python | ||
def knapsack(items, capacity): | ||
"""O(nc) time | O(nc) space, where n == number of items, c == capacity""" | ||
knapsack_values = [[0 for col in range(capacity + 1)] for row in range(len(items) + 1)] | ||
|
||
for row in range(1, len(items) + 1): | ||
value = items[row - 1][0] | ||
weight = items[row - 1][1] | ||
for col in range(capacity + 1): | ||
if weight > col: # col here represents a given capacity | ||
knapsack_values[row][col] = knapsack_values[row - 1][col] | ||
else: | ||
knapsack_values[row][col] = max( | ||
knapsack_values[row - 1][col], | ||
knapsack_values[row - 1][col - weight] + value | ||
) | ||
|
||
return [knapsack_values[-1][-1], backtrack_items(knapsack_values, items)] | ||
|
||
def backtrack_items(values, items): | ||
""" | ||
Backtracks from the bottom right of the 2d array, finding all the items that were put in the knapsack. | ||
""" | ||
results = [] | ||
row = len(values) - 1 | ||
col = len(values[0]) - 1 | ||
|
||
while row > 0: | ||
if values[row][col] == values[row - 1][col]: | ||
row -= 1 | ||
else: | ||
results.append(row - 1) | ||
col -= items[row - 1][1] | ||
row -= 1 | ||
return list(reversed(results)) | ||
``` | ||
|
||
|
||
```python | ||
# test it out | ||
capacity = 10 | ||
items = [[1, 3], [4, 3], [5, 6], [6, 7]] | ||
|
||
knapsack(items, capacity) | ||
``` | ||
|
||
|
||
|
||
|
||
[10, [1, 3]] | ||
|
||
|
||
|
||
### Unit Tests | ||
|
||
|
||
```python | ||
# unit tests | ||
import unittest | ||
|
||
class KnapsackTestCase(unittest.TestCase): | ||
def test_case_1(self): | ||
capacity = 10 | ||
items = [[1, 3], [4, 3], [5, 6], [6, 7]] | ||
expected = [10, [1, 3]] | ||
self.assertEqual(knapsack(items, capacity), expected) | ||
|
||
def test_case_when_capacity_is_zero(self): | ||
capacity = 0 | ||
items = [[1, 3], [4, 3], [5, 6], [6, 7]] | ||
expected = [0, []] | ||
self.assertEqual(knapsack(items, capacity), expected) | ||
|
||
|
||
if __name__ == "__main__": | ||
unittest.main(argv=[""], exit=False) | ||
``` |
Oops, something went wrong.