mirror of
https://github.com/dholerobin/Lecture_Notes.git
synced 2025-03-17 14:49:57 +00:00
308 lines
6.6 KiB
Markdown
308 lines
6.6 KiB
Markdown
Recursion and Backtracking 2
|
||
----------------------------
|
||
|
||
```
|
||
https://www.interviewbit.com/problems/kth-permutation-sequence/
|
||
https://www.interviewbit.com/problems/number-of-squareful-arrays/
|
||
https://www.interviewbit.com/problems/gray-code/
|
||
https://www.interviewbit.com/problems/combination-sum-ii/
|
||
https://www.interviewbit.com/problems/nqueens/
|
||
https://www.interviewbit.com/problems/all-unique-permutations/
|
||
https://www.interviewbit.com/problems/sorted-permutation-rank/
|
||
https://www.interviewbit.com/problems/word-break-ii/
|
||
|
||
|
||
|
||
https://www.interviewbit.com/problems/palindrome-partitioning/
|
||
https://www.interviewbit.com/problems/unique-paths-iii/
|
||
```
|
||
|
||
|
||
Permutations
|
||
------------
|
||
|
||
> Given String containing distinct characters. Print all permutations of the string
|
||
>
|
||
|
||
Approach:
|
||
|
||
Fix the first char
|
||
|
||

|
||
|
||
Can essentially be achieved by swapping
|
||
|
||

|
||
|
||
```python
|
||
def permute(S, i):
|
||
if i == len(S):
|
||
print(S)
|
||
for j in range(i, len(S)):
|
||
S[i], S[j] = S[j], S[i]
|
||
permute(S, i+1)
|
||
S[i], S[j] = S[j], S[i] # backtrack
|
||
```
|
||
|
||
-- --
|
||
|
||
Lexicographic permutations
|
||
--------------------------
|
||
|
||
asked in Amazon
|
||
|
||
- start with sorted elements
|
||
- instead of swap, do right rotation(i to j). Undo = left rotate
|
||
- swap was O(1), whereas rotation is O(n)
|
||
|
||
-- --
|
||
|
||
|
||
Unique Permutations, when string has duplicates
|
||
-----------------------------------------------
|
||
|
||

|
||
|
||
Basically, if we're swapping S[i] with S[j], but S[j] already occured earlier from S[i] .. S[j-1], then swapping will result in repetition
|
||
|
||
```python
|
||
def permute_distinct(S, i):
|
||
if i == len(S):
|
||
print(S)
|
||
|
||
for j in range(i, len(S)):
|
||
if S[j] in S[i:j]:
|
||
continue
|
||
S[i], S[j] = S[j], S[i]
|
||
permute_distinct(S, i+1)
|
||
S[i], S[j] = S[j], S[i] # backtrack
|
||
```
|
||
|
||
-- --
|
||
|
||
Kth Permutation Sequence
|
||
------------------------
|
||
> Given A[N] and k,
|
||
> find the kth permutation
|
||
>
|
||
|
||
[Kth Permutation Sequence - InterviewBit](https://www.interviewbit.com/problems/kth-permutation-sequence/)
|
||
|
||
$\dfrac{k}{(n-1)!}$ will give us the index of the first digit. Remove that digit, and continue
|
||
|
||
|
||
```python
|
||
def get_perm(A, k):
|
||
perm = []
|
||
while A:
|
||
# get the index of current digit
|
||
div = factorial(len(A)-1)
|
||
i, k = divmod(k, div)
|
||
perm.append(A[i])
|
||
# remove handled number
|
||
del A[index]
|
||
return perm
|
||
```
|
||
|
||
-- --
|
||
|
||
Sorted Permutation Rank
|
||
-----------------------
|
||
> Given S, find the rank of the string amongst its permutations sorted lexicographically.
|
||
> Assume that no characters are repeated.
|
||
>
|
||
```
|
||
Input : 'acb'
|
||
Output : 2
|
||
|
||
The order permutations with letters 'a', 'c', and 'b' :
|
||
abc
|
||
acb
|
||
bac
|
||
bca
|
||
cab
|
||
cba
|
||
```
|
||
|
||
**Hint:**
|
||
If the first character is X, all permutations which had the first character less than X would come before this permutation when sorted lexicographically.
|
||
|
||
Number of permutation with a character C as the first character = number of permutation possible with remaining $N-1$ character = $(N-1)!$
|
||
|
||
**Approach:**
|
||
|
||
rank = number of characters less than first character * (N-1)! + rank of permutation of string with the first character removed
|
||
|
||
```
|
||
Lets say out string is “VIEW”.
|
||
|
||
Character 1 : 'V'
|
||
All permutations which start with 'I', 'E' would come before 'VIEW'.
|
||
Number of such permutations = 3! * 2 = 12
|
||
|
||
Lets now remove ‘V’ and look at the rank of the permutation ‘IEW’.
|
||
|
||
Character 2 : ‘I’
|
||
All permutations which start with ‘E’ will come before ‘IEW’
|
||
Number of such permutation = 2! = 2.
|
||
|
||
Now, we will limit ourself to the rank of ‘EW’.
|
||
|
||
Character 3:
|
||
‘EW’ is the first permutation when the 2 permutations are arranged.
|
||
|
||
So, we see that there are 12 + 2 = 14 permutations that would come before "VIEW".
|
||
Hence, rank of permutation = 15.
|
||
```
|
||
|
||
|
||
[Sorted Permutation Rank - InterviewBit](https://www.interviewbit.com/problems/sorted-permutation-rank/)
|
||
|
||
|
||
-- --
|
||
|
||
Number of Squareful Arrays
|
||
--------------------------
|
||
|
||
> Given A[N]
|
||
> array is squareful if for every pair of adjacent elements, their sum is a perfect square
|
||
>
|
||
> Find and return the number of permutations of A that are squareful
|
||
>
|
||
|
||
|
||
> Example:
|
||
> A = [2, 2, 2]
|
||
> output: 1
|
||
>
|
||
> A = [1, 17, 8]
|
||
> output: 2
|
||
> [1, 8, 17], [17, 8, 1]
|
||
>
|
||
|
||
|
||
```python
|
||
def check(a, b):
|
||
sq = int((a + b) ** 0.5)
|
||
return (sq * sq) == (a + b)
|
||
|
||
if len(A) == 1: # corner case
|
||
return int(check(A[0], 0))
|
||
|
||
count = 0
|
||
def permute_distinct(S, i):
|
||
global count
|
||
if i == len(S):
|
||
count += 1
|
||
|
||
for j in range(i, len(S)):
|
||
if S[j] in S[i:j]: # prevent duplicates
|
||
continue
|
||
if i > 0 and (not check(S[j], S[i-1])): # invalid solution - branch and bound
|
||
continue
|
||
S[i], S[j] = S[j], S[i]
|
||
permute_distinct(S, i+1)
|
||
S[i], S[j] = S[j], S[i] # backtrack
|
||
|
||
permute_distinct(A, 0)
|
||
return count
|
||
```
|
||
|
||
-- --
|
||
|
||
Gray Code
|
||
---------
|
||
> Given a non-negative integer N representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0.
|
||
> The gray code is a binary numeral system where two successive values differ in only one bit.
|
||
|
||
|
||
G(n+1) can be constructed as:
|
||
0 G(n)
|
||
1 R(n)
|
||
|
||
```
|
||
Example G(2) to G(3):
|
||
|
||
0 00
|
||
0 01
|
||
0 11
|
||
0 10
|
||
----
|
||
1 10
|
||
1 11
|
||
1 01
|
||
1 00
|
||
```
|
||
|
||
```python
|
||
def gray(self, n):
|
||
codes = [0, 1] # length 1
|
||
for i in range(1, n):
|
||
new_codes = [s | (1 << i) for s in reversed(codes)]
|
||
codes += new_codes
|
||
|
||
return codes
|
||
```
|
||
|
||
|
||
|
||
-- --
|
||
|
||
Combination Sum II
|
||
------------------
|
||
|
||
[Combination Sum II - InterviewBit](https://www.interviewbit.com/problems/combination-sum-ii/)
|
||
|
||
|
||
We already did this. Why couldn't you solve it!?
|
||
|
||
-- --
|
||
|
||
N Queens
|
||
--------
|
||
|
||
[NQueens - InterviewBit](https://www.interviewbit.com/problems/nqueens/)
|
||
|
||
Backtracking
|
||
|
||
- Place one queen per row
|
||
- backtrack if failed
|
||
|
||
|
||
-- --
|
||
|
||
Word Break II
|
||
-------------
|
||
|
||
> Given a string A and a dictionary of words B, add spaces in A to construct a sentence where each word is a valid dictionary word.
|
||
>
|
||
|
||
```
|
||
Input 1:
|
||
A = "catsanddog",
|
||
B = ["cat", "cats", "and", "sand", "dog"]
|
||
|
||
Output 1:
|
||
["cat sand dog", "cats and dog"]
|
||
```
|
||
|
||
```python
|
||
|
||
def wordBreak(A, B):
|
||
B = set(B)
|
||
sents = []
|
||
|
||
def foo(i, start, sent):
|
||
word = A[start:i+1]
|
||
|
||
if i == len(A):
|
||
if word in B:
|
||
sents.append((sent + ' ' + word).strip())
|
||
return
|
||
|
||
if word in B:
|
||
foo(i+1, i+1, sent + ' ' + word)
|
||
foo(i+1, start, sent)
|
||
|
||
foo(0, 0, '')
|
||
``` |