chapter 8 done ✔️

This commit is contained in:
anebz 2020-08-27 11:09:09 +02:00
parent 26ef14f71a
commit 679e95bda1
5 changed files with 265 additions and 0 deletions

View File

@ -0,0 +1,87 @@
# 8.2. Robot in a Grid
> Imagine a robot sitting on the upper left corner of grid with r rows and c columns. The robot can only move in two directions, right and down, but certain cells are "off limits" such that the robot cannot step on them. Design an algorithm to find a path for the robot from the top left to the bottom right.
Start going down, if you find some cell that can't be stepped on, go one right and down again. And so on.
```python
def go_bottom_down(r: int, c: int):
pos = [0, 0]
while pos[0] < r and pos[1] < c:
pos[0] += 1
step = can_step(pos)
while not step:
pos[1] += 1
step = can_step(pos)
```
## Hints
> For the robot to reach the last cell, it must find a path to the second-to-last cells. For it to find a path to the second-to-last cells, it must find a path to the tird-to-last cells.
I'm missing something.
> Simplify this problem by first figuring out if there's a path. Then, modify your algorithm to track the path.
But if there's no path to going down, I can go one right and try again. Why check if there's a path and then track it?
## Solution
To reach the point (r, c) we have to reach either (r-1, c) or (r, c-1). To reach (r-1, c), we can either reach (r-2, c) or (r-1, c-1). This memoization could be improved by storing the grid in memory, and whether it can be accessed or not.
You create a maze with True or False for the positions that can be stepped on.
```python
def get_path(maze):
if not maze or len(maze) == 0:
return None
path = []
if is_path(maze, len(maze)-1, len(maze[0])-1, path):
return path
return None
def is_path(maze, row, col, path):
# if out of bounds or not available, return
if col < 0 or row < 0 or not maze[row][col]:
return False
isAtOrigin = (row == 0) and (col == 0)
#if there's a path from the start to here, add my location
if isAtOrigin or isPath(maze, row, col-1, path) or isPath(maze, row-1, col,path):
path.append((row, col))
return True
return False
print(getPath([[True, True],[True,True]]))
```
This works, but many many locations are visited twice. Using memoization:
```python
def get_path_memoized(maze):
if maze == None or len(maze) == 0:
return None
path = []
visited_points = []
if is_path_memoized(maze, len(maze) - 1, len(maze[0]) - 1, path, visited_points):
return path
return None
def is_path_memoized(maze, row, col, path, visited_points):
if row < 0 or col < 0 or not maze[row][col] or (row, col) in visited_points:
return False
is_at_origin = row == 0 && col == 0
if is_at_origin or is_path_memoized(maze, row-1, col, path) or is_path_memoized(maze, row, col-1, path):
path.append((row, col))
return True
visited_points.append((row, col))
return False
print(get_path_memoized([[True,True], [False,True]]))
```

View File

@ -0,0 +1,44 @@
# 8.4. Power set
> Write a method that returns all subsets of a set
```python
def power_set(lst, subsets=[]):
for el in lst:
if len(el) > 0:
subsets.extend(power_set(el, subsets))
subsets.append(lst)
return subsets
lst = [1, 2, [3, 4], [[5], [6,7]]]
subsets = power_set(lst)
```
## Hints
I understood the problem wrong.
* If you have {a, b}, all the subsets are: a, b, ab
* If you have {a, b, c}, all the subsets are: [a, b, ab], c, ac, bc, abc
* If you have {a, b, c, d}, all the subsets are: [a, b, ab, c, ac, bc, abc], ad, bd, cd, abd, acd, bcd, abcd.
For any new letter, add the last letter to all the subsets and append.
> You can also map each subset to a binary number, the `i`th bit could represent a 'boolean' flag for whether an element is in the set.
I can also use a python set.
```python
def power_set(lst):
subsets = set()
subsets.add(lst[0])
for el in lst:
for subs in subsets:
subsets.add(subs + el)
subsets.add(el)
return subsets
power_set([1, 2, 3, 4])
```
The complexity of this algorithm is O(n * 2^n) in space and time.

View File

@ -0,0 +1,52 @@
# 8.7. Permutations without duplicates
> Write a method to compute all permutations of a string of unique characters
* s = anebz
* s = an, size=2
- permutations = an, na
- total 4
* s = ane, size=3
- permutations = ean, ane, ena, nae + aen + nea
- total 6, 3\*2
* s = aneb, size=4
- permutations = aneb, anbe, aben, abne, aenb, aebn
- baen, bane, bean, bena, bnae, bnea
- eabn, eanb, eban, ebna, enab, enba
- nabe, naeb, nbae, nbea, neab, neba
- total 24, 4\*3\*2
In each iteration, add the new word in each position of the previous permutations. for 'an' and new letter 'e', it becomes ean, aen, ane.
```python
def permutations(s):
prm = [s[0]]
for char in s[1:]:
for p in list(prm):
for i in range(len(p)):
prm.append(p[:i] + char + p[i:])
return prm
```
This would have complexity of O(len(s)!) for each character in s. Therefore O(n * n!) = O((n+1)!). Checked example 12 on p51 and it's correct (section 1.9 in the [Introduction](../introduction.md))
## Hints
The hints describe what I have done =) Insert the new letter into each possible location of the previous permutations. You can create all permutations of abcd by computing all permutations of abc and then inserting d into each possible location within those.
```python
# approach 1: building from permutations of first n-1 characters
def permutations(s):
prm = []
if len(s) == 0:
prm.append("")
return prm
for word in permutations(s[1:]):
for i in range(len(word)):
prm.append(word[:i] + s[0] + word[i:])
return prm
print(permutations("str"))
```
For a word like 'str', it goes deep into the function until len(s) == 0, then returns '', we go up to 'r', and adds 'r' to each position. We end up with 'r'. Go up, iterate prm ('r') and add 't' to each position. And so on.

View File

@ -0,0 +1,77 @@
# 8.8. Permutations with duplicates
> Write a method to compute all permutations of a string whose characters are not necessarily unique. The list of permutations should not have duplicates.
solution in 357
The easiest solution would be to create a set instead of a list.
* s = anee
* s = an, size=2
- permutations = an, na
- total 4
* s = ane, size=3
- permutations = ean, ane, ena, nae + aen + nea
- total 6, 3\*2
* s = anee, size=4
- permutations = anee, aeen, aene
- eaen, eane, eean, eena, enae, enea
- naee, neae, neea
- total 12
```python
# approach 1: building from permutations of first n-1 characters
def permutations(s):
prm = set()
if len(s) == 0:
prm.append("")
return prm
for word in permutations(s[1:]):
for i in range(len(word)):
prm.add(word[:i] + s[0] + word[i:])
return prm
print(permutations("str"))
```
## Hints
If there are many duplicate letters, it becomes inefficient to check the set each time.
> Get the count of each character, abcaac has 3a, 2c and 1b
How does that help? How can I omit doing all the permutations and checking if that permutation is already there?
> Pick a starting character. a, b, c. If you start with a, then get all permuations for 2a, 2c and 1b.
## Solution
Worst case will be O((n+1)!), but in other cases we want to only create the unique permutations.
Permutations of (a=3, b=1, c=2) is P(2, 1, 2) + P(3, 0, 2) + P(3, 1, 1) and so on recursively for each starting character.
```python
def printPerms(string):
result = []
letterCountMap = defaultdict()
for letter in string:
letterCountMap[letter] += 1
printPermsInner(letterCountMap, "", len(string), result)
return result
def printPermsInner(letterCountMap, prefix, remaining, result):
#base case Permutation has been completed
if remaining == 0:
result.append(prefix)
return
#try remaining letter for next char, and generate remaining permutations
for character in letterCountMap:
count = letterCountMap[character]
if count > 0:
letterCountMap[character] -= 1
printPermsInner(letterCountMap, prefix + character, remaining - 1, result)
letterCountMap[character] = count
print(printPerms("aaf"))
```

View File

@ -70,7 +70,12 @@ If you can't afford to buy the book, you can find a free pdf [here](http://ahmed
## Chapter 8 Recursion
* Triple step
* Robot in grid
* Magic index (index such that A[i] = 1)
* Power set
* Permutations of string with unique characters
* Permutations of string with duplicate characters
## Chapter 10 Sorting and searching