Skip to content

Commit

Permalink
Add dynamic programming solutions
Browse files Browse the repository at this point in the history
  • Loading branch information
romarowski committed Feb 24, 2024
1 parent 9c86e05 commit f7e7ea0
Show file tree
Hide file tree
Showing 20 changed files with 224 additions and 16 deletions.
11 changes: 11 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"python.testing.unittestArgs": [
"-v",
"-s",
".",
"-p",
"test_*.py"
],
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true
}
3 changes: 3 additions & 0 deletions 01-string.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## String


27 changes: 27 additions & 0 deletions 03-binary_tree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
## Binary Tree

### Tree height problem

**Statement**: Given a binary tree, find its height.

**Approach**: Transverse the tree, keeping track of the height of the left and right subtrees. Return the maximum height.
1. Base case: empty (or null) tree has height -1.
2. Recursive case: return 1 + the maximum height of the left and right subtrees.


```python
def height(node):

# empty tree
if node is None:
return -1

# recursive case
return 1 + max(height(node.left), height(node.right))
```

**Complexity**:
- Time: O($n$), need to transverse every node on the tree.
- Space: O($n$), we have n calls to ```height()```.


25 changes: 25 additions & 0 deletions 05-dynamic-programming.md → 05-dynamic_programming.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
## Dynamic Programming

## Concepts I don't understand:

- [ ] Time complexity in brute force sum possible??


### Fibonacci sequence problem

**Statement:** Given a number ```n``` $\in\N$, find the its Fibonacci number.
Expand Down Expand Up @@ -33,4 +38,24 @@ A better approach is to use **dynamic programming** and store the results of the
- Time: $O(n)$
- Space: $O(n)$

### Sum possible problem

**Statement:** Given a list of numbers $\text{nums}=[n_1, n_2, ..., n_n]$ and a target amount $a$, find if it is possible to obtain the target sum using the numbers in the list.

**Approach**:
Is possible to solve this problem with brute force recursion. The idea is to substract all possible combinations of ```nums``` from ```a``` until reaching 0.

1. Code the two base cases:
a. Amount is 0, then we succesfully got to $a$.
b.


```python
def sum_possible(a, nums):
if a < 0:
return False
if a == 0:
return True



Empty file added __init__.py
Empty file.
50 changes: 34 additions & 16 deletions dynamic_programming/sum_possible.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,52 @@
You may assume that the target amount is non-negative.
"""

def sum_possible(amount, numbers):
for n in numbers:
possible = recur(amount, n, numbers)
if possible:
return True
##############################
# dynamic programming O(a*n) #
##############################

return False
def sum_possible(amount, numbers):
calculated = dict()
return _sum_it(amount, numbers, calculated)

def recur(remainder, subtrahend, numbers):

if subtrahend > remainder:
return
def _sum_it(amount, numbers, calculated):
if amount < 0:
return False

remainder = remainder - subtrahend

if remainder == 0:
if amount == 0:
return True

if amount in calculated:
return calculated[amount]

for n in numbers:
if _sum_it(amount-n, numbers, calculated):
calculated[amount] = True
return True

calculated[amount] = False
return False

return False

print(sum_possible(4, [1, 2, 3,])) # -> True, 4 + 4


#################################
# brute force recursion O(n**a) #
#################################

#def sum_possible(amount, numbers):
# if amount < 0:
# return False
#
# if amount == 0:
# return True
# for n in numbers:
# if sum_possible(amount-n, numbers):
# return True
#
# return False

print(sum_possible(4, [1, 2, 3,])) # -> True, 4 + 4

###############################
# solution with n! complexity #
Expand Down
Empty file added string_array/__init__.py
Empty file.
Binary file added string_array/__pycache__/__init__.cpython-310.pyc
Binary file not shown.
Binary file not shown.
File renamed without changes.
File renamed without changes.
44 changes: 44 additions & 0 deletions string_array/greatest_common_divisor_of_strings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""
1071. Greatest Common Divisor of Strings
Easy
For two strings s and t, we say "t divides s" if and only
if s = t + t + t + ... + t + t (i.e., t is concatenated with
itself one or more times).
Given two strings str1 and str2, return the largest string x
such that x divides both str1 and str2.
"""

def gcdOfStrings(str1, str2):
m = len(str1)
n = len(str2)

if m>=n:
divisor = str2
word = str1
else:
divisor = str1
word = str2

static_divisor = divisor
cur = len(divisor)
while cur > 0:
remainder = len(word) % len(divisor)
if remainder==0:
k = int((len(word)/len(divisor)))
divisable = word == divisor * k
if divisable:
if len(static_divisor) % len(divisor) == 0:
return divisor

cur-=1
divisor = divisor[:cur]
return ""



if __name__ == "__main__":
print(gcdOfStrings("ABCABC", "ABC")) # -> "ABC"
print(gcdOfStrings("ABABAB", "AB")) # -> "AB"
File renamed without changes.
38 changes: 38 additions & 0 deletions string_array/merge_strings_alternatively.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
1768. Merge Strings Alternately
Easy
You are given two strings word1 and word2.
Merge the strings by adding letters in alternating order,
starting with word1. If a string is longer than the other,
append the additional letters onto the end of the merged string.
Return the merged string.
"""

def mergeAlternatively(word1, word2):
cur1 = 0
cur2 = 0
ans = ""

while cur1 < len(word1) and cur2 < len(word2):
ans += word1[cur1] + word2[cur2]

cur1+=1
cur2+=1

if cur1 == len(word1):
if cur2 < len(word2):
ans+=word2[cur2:]
return ans

if cur2 == len(word2):
if cur1 < len(word1):
ans+=word1[cur1:]
return ans
return ans



print(mergeAlternatively("abc","pqr")) #-> "apbqcr"
1 change: 1 addition & 0 deletions string_array/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import sys
Binary file not shown.
Binary file not shown.
41 changes: 41 additions & 0 deletions string_array/tests/test_greatest_common_divisor_of_strings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import unittest as ut
from string_array.greatest_common_divisor_of_strings import gcdOfStrings


class TestGCDOfStrings(ut.TestCase):
def test_common_divisor_exists(self):
str1 = "ABCABC"
str2 = "ABC"
expected_output = "ABC"
self.assertEqual(gcdOfStrings(str1, str2), expected_output)

def test_no_common_divisor(self):
str1 = "ABABAB"
str2 = "CD"
expected_output = ""
self.assertEqual(gcdOfStrings(str1, str2), expected_output)

def test_empty_strings(self):
str1 = ""
str2 = ""
expected_output = ""
self.assertEqual(gcdOfStrings(str1, str2), expected_output)

def test_same_string(self):
str1 = "XYZ"
str2 = "XYZ"
expected_output = "XYZ"
self.assertEqual(gcdOfStrings(str1, str2), expected_output)

def test_long_string(self):
str1 = "TAUXX" * 5
str2 = "TAUXX" * 9
expected_output = "TAUXX"
self.assertEqual(gcdOfStrings(str1, str2), expected_output)


def test_more_strings(self):
str1 = "AAAAAAAAA"
str2 = "AAACCC"
expected_output = ""
self.assertEqual(gcdOfStrings(str1, str2), expected_output)
File renamed without changes.
File renamed without changes.

0 comments on commit f7e7ea0

Please sign in to comment.