Add all my notes

This commit is contained in:
Pragy Agarwal
2020-03-19 12:51:33 +05:30
parent 6d6aa54e32
commit 35e83b39a2
110 changed files with 7710 additions and 0 deletions

View File

@@ -0,0 +1,243 @@
Arrays + 2d Arrays
------------------
anish - disruptor
Vivek - May EliteX
-- --
pragy@interviewbit.com
Sum of all Submatrices
----------------------
> Given matrix $M_{n \times n}$, find the sum of all submatrices of M
>
> Example:
>
> 1 1
> 1 1
>
> sum = 1 + 1 + 1 + 1 + 2 + 2 + 2 + 2 + 4
> = 16
>
![10417df8.png](/users/pragyagarwal/Boostnote/attachments/58e5d3fa-9fb3-4fac-8589-df43c99e4851/10417df8.png =250x)
**Brute Force**
Go over each submatrix, and add
- Submatrix is a rectangle - topleft and bottomright points
- So, four for loops to decide a submatrix (two for topleft, 2 for bottomright)
- then, two for loops to go over each element in the submatrix
Complexity: $O(n^6)$
```python
total = 0
top <- 0 .. n
left <- 0 .. n
bottom <- top .. n
right <- left .. n
i <- top .. bottom
j <- left .. right
total += M[i][j]
```
**Optimized**
![50177743.png](/users/pragyagarwal/Boostnote/attachments/58e5d3fa-9fb3-4fac-8589-df43c99e4851/50177743.png =150x)
- Element i, j appears in multiple submatrices
- If a[i][j] occurs in $k$ submatrices, its contribution to the total is $k \times a[i][j]$
- So, we need to count the number of occurances of each i, j
![f9420692.png](/users/pragyagarwal/Boostnote/attachments/58e5d3fa-9fb3-4fac-8589-df43c99e4851/f9420692.png =400x)
Just count the number of submatrices that contain $i, j$ - choose any top right from allowed, choose any bottom right from allowed
For top-right: $(i+1)(j+1)$
For bottom-left: $(n-i) (n-j)$
Total for $i, j = (i+1)(j+1)(n-i)(n-j)$
So, contribution = $a[i][j] \times (i+1)(j+1)(n-i)(n-j)$
$O(n^2)$
-- --
This is called reverse lookup
(not to be confused with inverting the problem)
-- --
Any Submatrix Sum
------------------
> Given $M_{m \times n}$
> $q$ queries, $q$ is large, of the form (top-left, bottom-right)
> Find the sum of the submatrix specified by each query
>
**Naive**
$O(qmn)$
**Optimized**
Calculate Prefix Sums
- explain for 1d array
- extend to 2d array
![b3741590.png](/users/pragyagarwal/Boostnote/attachments/58e5d3fa-9fb3-4fac-8589-df43c99e4851/b3741590.png)
First by rows, then by columns (or vice versa)
Now, add and substract sum to get the desired sums
![89352278.png](/users/pragyagarwal/Boostnote/attachments/58e5d3fa-9fb3-4fac-8589-df43c99e4851/89352278.png)
Prefix Sum matrix = P
$sum(top, left, bottom, right) = P(bottom, right) - P(bottom, left - 1) - P(top-1, right) + P(top-1, left-1)$
**Corner cases**
-- --
Max Submatrix Sum
------------------
> Given Matrix
> All rows are sorted
> All columns are sorted
> Find the max sum submatrix
>
![cf7e8a03.png](/users/pragyagarwal/Boostnote/attachments/58e5d3fa-9fb3-4fac-8589-df43c99e4851/cf7e8a03.png =300x)
**Brute force** $O(n^6)$
**All submatrices using prefix sum** $O(n^4)$
**Optimal**
Create suffix sums of matrix
find max value
$O(n^2)$
-- --
Find number ZigZag
------------------
> Given matrix
> Each row and column is sorted
> Find a given number $k$
>
**Approach 1**
Binary search each row/column
$O(n \log n)$
**Optimal**
![237e989f.png](/users/pragyagarwal/Boostnote/attachments/58e5d3fa-9fb3-4fac-8589-df43c99e4851/237e989f.png =300x)
Start from top right of the remaining matrix
If $k$ is larger, scrape off the row
If $k$ is smaller, scrape off the column
In every iteration, we scrape off one row or column
Complexity: $O(m+n)$
-- --
Chunks
------
> Given Array
> A[N]
> $A[i] \in \{0 .. N-1\}$
> All elements are distinct
>
The array is a permutation
> 1. Split the array into chunks $C_1, C_2, C_3 \ldots$
> 2. Sort individual chunks
> 3. Concatenate
>
> The array after these operatio0ns should be sorted
> Find the max number of chunks that the array can be split into
>
minimizing? ans: 1
sorted array (max)? ans: |A|
reverse sorted? 1
**Observation**
For $i$ to $j$ to be a valid chunk, it has to contain all the numbers $i$ to $j$
**Approach**
Compute max from left to right. If at any point, max == i, we have a chunk
So, do a chunk++
If max > i, can we jump to i? No. because there might be something even greater on the way
Can max < i? No
--- ---
--- ---
Lecture bookmarks
mine -
00:04:00 Lecture Start
00:04:29 Q1 - Find sum of all submatrices of given Matrix
00:05:28 Q1 - Example
00:08:00 Q1 - Brute Force Approach
00:15:30 Q1 - Optimized (Intuition)
00:19:28 Q1 - Optimized (Approach)
00:24:56 Q1 - Optimized - Formula re-explanation
00:27:30 Pattern: Reverse lookup
00:28:16 Q2 - Answer many submatrix sum Queries
00:30:30 Q2 - Brute Force Approach
00:31:20 Q2 - 1D Array Prefix Sum
00:35:20 Q2 - Extending prefix-sum to Matrices
00:46:25 Q2 - Corner Cases
00:48:07 Q3 - Given Matrix with rows & columns sorted, find Largest sum submatrix
00:49:42 Q3 - Brute Force Approach
00:50:47 Q3 - Optimization 1
00:52:38 Q3 - Optimization 2
01:00:07 Q4 - Given Matrix with rows & columns sorted, search for some key k
01:00:47 Q4 - Binary Search Approach
01:03:27 Q4 - ZigZag approach
01:15:22 Q5 - Max number of chunks
01:18:18 Q5 - Example
01:20:18 Q5 - Special Cases
01:22:47 Q5 - Observations
01:25:20 Q5 - Optimized
01:29:15 Q5 - Example Run
01:30:15 Q5 - Pseudo Code
01:32:20 Doubt Clearing

View File

@@ -0,0 +1,169 @@
Binary Search
-------------
- needs ordering (not necessarily sorting, since orderings can be of more than one type)
- basically, some proposition which makes
```
N N N N N N Y Y Y Y Y Y Y
```
- ask about how many people are encountering Binary Search for the first time
- quickly explain Binary Search. Ask if everyone can implement it
- Recurrennce implementation
Implementation of Binary Search
-------------------------------
- loop till low <= high
- Computing mid:
```
m = (l+h) / 2
```
vs
```
m = l + (h-l)/2
```
Time complexity
---------------
- Recurrence for time complexity: $T(n) = T(n/2) + O(1)$
- Solve this recurrence to show complexity is $O(\log_2 n)$
Ternary Search
--------------
- Ternary Search: $T(n) = T(n/3) + O(1)$
- Ternary Search isn't really faster. Since $O(1)$ of binary search is less than $O(2)$ of ternary search. $1 \times \log_2 n < k \times \log_k n$. Extreme Case: $k=n$, n-ary search, which is same as linear search
Eventual value of low and high if element is not present?
---------------------------------------------------------
- if searching for $x$, after termination, $A_l >= x$ while $A_h <= x$
- Note that the roles are reversed
Repeated elements, Find first occurance of element
-------------------------------
- when `array[mid] == x`, either we've hit the first occurance or hit the not-first occurance.
- if `array[mid] == x` then check if `array[mid - 1] == x`. If yes, do `high = mid - 1` and continue, since this is not the first occurance.
- edge case: if `mid = 0`, then make sure that you don't check `array[-1]`
-- --
Rotated array:
--------------
- if shifted to the right
- `6 7 8 9 0 1 2 3 4 5`
- `A[0] >= A[-1]`. If this is not true, there was no rotation
- Now, we have mid, let's say 2
- Now, if 2 is in the first half, then it must be greater than last element
- Else it should be smaller than last element.
- So search for rotation point based on this
Find any peak element in _unsorted_ array
------------------------------------------
- Peak element is one that is not smaller than its neighbors
- 1, **5**, 3, 2, 1, **6**, 5
- $\log n$ time using binary search
- if sorted ascending, peak is last
- if sorted descending, first element is peak
- algo:
- check mid.
- 1 6 5
- if `a[m-1] <= a[m] >= a[m+1]`, then peak
- 7 6 5
- if `a[m-1] > a[m] >= a[m+1]`, then move left
- theorem: one peak exists to the left
- 90 80 70 60 50
- ofcourse, there could be a peak to the right, but we can safely go left
- 7 6 8
- move in either of the parts, since peaks exist on both sides
All but one element comes twice, find this element. Sorted array
----------------------------------------------------------------
- 0 0 4 4 **5** 7 7 8 8
- get mid. find its first occurance in log n time.
- check if number of elements from mid to last is even or odd.
- odd: singular exists in latter part
- even: singular exists in former part
Family of strings
-----------------
- $s_0 = 0$
- $s_i = s_{i-1} \cdot 0 \cdot (s_{i-1})'$
```
s0 = 0 1
s1 = 001 3
s2 = 0010110 7
s3 = 001011001101001 15
```
- Given N, k, find kth character of $S_n$.
- Length of string: $|S_n| = 2^{n+1} - 1$
- Draw tree. Show toggling of bits
Staircase
---------
```
__
__|__|
__|__|__|
__|__|__|__|
|__|__|__|__|
```
- heights: 1, 2, ... h
- Given $n$ bricks, find the max height of staircase that can be built
- Let ans be $h$. Then number of bricks needed = $h(h+1) / 2$
- Now, binary search on h. Min = 0, max = n.
- if f(h) > n, go left
- if f(h) < n and f(h+1) >= n. Stop
- if f(h) < n and f(h+1) < n, go right
-
MxN Matrix. Each row sorted. MxN is odd. Find overall median
------------------------------------
$M \times N$ matrix. Note: $M \times N$ is odd.
```
4 6 7
1 7 9
2 2 3
```
actual answer: 4
1 2 2 3 **4** 6 7 7 9
- Vanilla - concat and sort arrays. $O(mn \log{mn})$
- Median of Medians doesn't work, 7 is not the correct answer
- Note: lowest element is from 1st col, and largest is from last col (since rows are sorted)
- M rows. Find low and high in O(m) time
- Now, if x is median, then 1/2 elements should be smaller, 1/2 should be bigger
- more correctly, if x is repeated, then if first occurance of x is l, last occurance is r, then if l <= n/2 <= r, then x is median
- now, in each row, find how many >x and <x.
- if l <= n/2 <= r - stop
- if r < n/2, increase low
- if l > n/2, decrease high
- Time complexity: $O(m \log n \log{(\max - \min)})$
- why odd? 1 4 6 9, and searching for 5. both side are n/2 so we don't know what to increase/decrease
Any doubts, will you be able to code it?
----------------------------------------
-- --
- 4 things
- lecture 1 hour
- assignment (4 questions) same which were discussed in class
- standup session (homework problem / doubts)
- homework problem
- 2 links generated - standup lecture and lecture
- operations guy will help setting up of lectures
- TAs will take a standup session, not me
- share questions and homeworks

View File

@@ -0,0 +1,101 @@
Binary Search 2
---------------
Median of two sorted arrays
---------------------------
- merge: O(n). Search O(log n)
- binary search: O(log n)
- pick the smaller array
- low = 0, high = length of smaller array
- partition the other array so that number of elements in first of both = number of elements in last of both
- now check if this partition is valid by cross comparison
- change high and low accordingly
- append -inf and +inf to start and ends of arrays
Special Integer
-------------------------------------
> Unsorted array of size N.
> +ve numbers.
> Given X, find max value of K such that no subarray of length k has sum > x
- binary search over k in 0..N
- if any sum > X, k is not the answer
- if sum <= x, k might be the answer if k+1 is not allowed
- finding max sum for a given k takes O(n) time
- todo: change to m and not m-1/m+1 loop till h-l>1
-- --
Sorted array of length N.
-------------------------------------
> numbers are from 1..N-1 (so contiguous).
> One of the numbers is repeated.
> Find it
- 1 2 3 4 4 5 6 7 8 (number)
- 0 1 2 3 4 5 6 7 8 (index)
- N N N N Y Y Y Y Y (proposition)
Agressive Cows
--------------
> N stalls, n >= 2
> C cows, c >= 2
> locations of stalls, let's say 1, 2, 5, 7, 8
> Maximize the minimum distance between any two cows
- low = 1
- high = N
- calculate mid = distance, and check
Smallest Good Base
------------------
> $N \in \{3, 10^{18}\}$
> k >= 2
> $(N)_k = 1111111\ldots$
> Find smallest k
- example: N = 7
- k = 2, $(7)_2 = 111$
- finding the largest good base is trivial - N-1
- low = 2, high = n-1
- If $m$ is the answer, then $\exists i: 1 + m + m^2 + \cdots + m^i = N$
- But we still can't binary search since we don't know $i$. $i$ will change for different numbers
- Also, say we found a working or non working m. How do we change the low and high? Multiple possible answers, which one to chose?
- Let's look at it from searching on i
- We need to maximize i (thereby minimize k)
- $(7)_6 = 11, (7)_2 = 111$, we need to output 2.
- So, linear search over all possible number of bits from 63 to 2
- Then for a fixed (i), binary search for the value of m (or use formula of geometric series)
- low, high for number of bits will be $1, \log_2 N$ (because smallest k is 2)
- $2^{63} \approx 10^{18}$
Smallest subarray
-----------------
> Array of length N
> Not sorted
> +ve numbers
> Find length of smallest subarray such that sum >= k
- calculate prefix sum (prefix sum is sorted)
- can you calculate sum a[i] .. a[j]?
- a[i] .. a[j] = P[j] - P[i] + a[i]
- now, let's say the answer starts from S and ends at E
- loop over all possible S
- binary search for E
- return S, E that has min distance
Election
--------
> N People
> influence[1..n]: 1 2 2 3 1 (+ve)
> Voting: ith person votes for jth person if sum(influence[i+1:j-1]) <= influence[i]
> Note: j can lie on the left side as well
> Print the array of votes each person got
- So, in 1 2 2 3 1, the number of people who can vote for a[i] are 2 3 2 3 3
- now, if we try to find how many people vote for i, it is linear search, so total $O(n^2)$
- instead, we can calculate prefix sum, and for each person, see what range of people it can vote for using binary search. So O(n \log n)
- Now that we have ranges, we need to find the final array
- O(n) algo to convert ranges to array by doing +1 on start, -1 on end, and then taking prefix sum

View File

@@ -0,0 +1,163 @@
Binary Trees 2
--------------
Lowest Common Ancestor
---------------------
> LCA(n1, n2) is the node which is accessible from both n1, n2 (while going up), and is farthest from the root
> Given a Tree and 2 nodes, find LCA
> k-ary tree
**Approach 1:**
- traverse from each node to root - bottom up
- compare the two paths from left to right
- O(n^2) time, O(n) space
**Approach 2:**
- traverse from each node to root - bottom up
- compare from root to node - top down
- O(n) time, O(n) space
**Approach 3:**
- don't store all parents. Use linked list intersection technique
- count the height of each path.
- traverse the longer path so height is same
- move up together
- stop when same node
- O(1) space
> Can't go from child to parent?
> Don't have pointers to nodee we have values which must be searched
> Distinct values
```python
def lca(key1, key2, node):
if node.value in [key1, key2]:
return node
left = lca(key1, key2, node.left)
right = lca(key1, key2, node.right)
if left is not None and right is not None:
return node
if left is not None:
return left
if right is not None:
return right
return None
lca(key1, key2, root)
```
-- --
Isomorphism
-----------
> Rotate tree to reach another row
```python
def isomorphic(node1, node2):
if node1 != node2:
return False
# binary
if isomorphic(node1.left, node2.left) and isomorphic(node1.right, node2.right):
return True
if isomorphic(node1.left, node2.right) and isomorphic(node1.right, node2.left):
return True
return False
# O(n). Each node visited at most twice
# k-ary
for children1 in permute(node1.children):
for children2 in permute(node2.children):
passed = True
for c1, c2 in zip(children1, children2):
if not isomorphic(c1, c2):
passed = False
break
if passed:
return True
return False
# sort tree in level order recursively first, then compare
```
-- --
Longest Increasing Consequtive Sequence
--------------------------------------------------
> has to be top-down
> has to be connected
> has to be continuous (1-2-3 is okay, 1-3-5 is not)
>
- recursive
- func returns length of the LICS at node
- find LICS of left and right
- if left = node + 1, then LICS+1
- max of left, right
-- --
Create Next Pointers with O(1) space
------------------------------------
- Simple using O(n) space. Just do level order traversal
- can't use recursion either, because have to maintain call stack, which is O(h)
- todo
```python
level_start = root
while level_start:
cur = level_start
while cur is not None:
if cur.left:
if cur.right:
cur.left.next = cur.right
else:
cur.left.next = get_next_child(cur)
if cur.right:
cur.right.next = get_next_child(cur)
cur = cur.next
if level_start.left:
level_start = level_start.left
elif level_start.right:
level_start = level_start.right
else:
level_start = None
def get_next_child(node):
iterate to get the child, till children exist
if not, then move to node.next
guaranteed to have precomputed the next
```
-- --
Boundary of tree
----------------
Tree of same sum
----------------
-- --
> Why cant decide tree using pre+post order? why need inorder?
inorder: lst root rst
preorder: root lst rst
postorder: lst rst root
if just have preorder+postorder, can't separate lst-rst

View File

@@ -0,0 +1,285 @@
Bit Manipulation
----------------
Bitwise AND &
-------------
3 & 5
011 & 101
= 001
= 1
Bitwise OR |
------------
3 | 5
011 | 101
= 111
= 7
XOR ^
-----
Exclusive OR. Either this, or that
That is, both bits are different.
For more than 2 bits, True when number of on bits is odd
-- --
```
a & 0 = 0 a & 1 = a a & a = a
a | 0 = a a | 1 = 1 a | a = a
a ^ 0 = a a ^ 1 = ~a a ^ a = 0
```
For all these 3 operations, associativity is followed
so, $a \odot b \odot c = (a \odot b) \odot c = a \odot (b \odot c)$
-- --
Masking property of XOR
-----------------------
b = (a^b) ^ a
= (a^b) ^ a
= b ^ (a^a)
= b^ 0
= b
-- --
Shifts
------
`<< k` - shift left by k. Insert 0 on right
`>> k` - shift right by k.
`<< k` = multiply by $2^k$
`>> k` = integer divide by $2^k$
show with example, say 22 = 10110
-- --
find first set bit
------------------
simply loop from i = 1 to 64.
check if x & (1<<i) is non-zero
-- --
Pair with XOR
-------------
> Given A[N], find any pair of elements whose XOR is k
>
**Brute Force:**
Consider all pairs. $O(n^2)$
If a[i] ^ a[j] = k, then a[j] = k ^ a[i]
So, for each a[i]. I need to find if k^a[i] also exists in the array.
Use a hashmap - O(n)
**Corner Case**
if k = 0, we need to search for repeated elements.
So, make sure that you handle it separately.
If we don't handle separately, we might have to store a list of values for each number, which will be bad.
-- --
Single Out
----------
> Given A[N] in which each number appears twice, except for one number. Find this number
>
**Naive:**
Hashmap. O(n) space
**Optimized:**
Masking property of xor - each repeated number will unmask itself.
So, simply xor the entire array.
Space complexity: O(1)
a^a = 0, a^0 = a
Order doesn't matter, so
a ^ b ^ a ^ c ^ b
a's will cancel out, b's will cancel out. Left with c
-- --
Double Out
----------
> Given A[N] in which each number appears twice, except for two numbers. Find these numbers
> 1 2 2 1 3 8 6 3
> Return 6, 8
>
**Naive:** Counter. O(n) space
**Optimized:**
- x = xor of entire array. You get xor of the tw oneeded elements
- find out any bit where the xor is set. We know that for this bit, our needed elements differ. So, partition by this bit
- Since all other numbers come in pairs, each partition will also have the numbers in pairs
- calculate the xor of individual partitions
![3e86c025.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/3e86c025.png =400x)
O(1) space
-- --
Tripled
-------
> Given A[N]. All elements occur thrice, exceopt one which occurs once. Find the single one.
>
**Naive:** Counter. O(n) space
**Optimized:**
Since numbers occurs thrice, for each bit, the count of 1s for that bit must be a multiple of 3. If it is not, then the single number must have that bit set.
So, construct that single number
![f51be358.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/f51be358.png =400x)
Complexity: $O(n \log \max)$
If max integer is 32 bits, then O(32n)
-- --
> Given A[N], find the pair with minimum xor
>
**Brute Force:** All pairs. Keep min. $O(n^2)$
**Optimized:**
Given a[i], best possibility is to find another a[i]
If not, then we can find a[i]-1 or a[i]+1
We basically want the numbers to be different as right as possible
![7ddd6b6e.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/7ddd6b6e.png)
Intuition: Sort the numbers. Lower the difference, lower the XOR.
**Proof:**
Consider A < B < C
suppose A, C differ in ith bit. Bits 0 to i-1 are same (from MSB)
Then, A must have a 0 there, while C must have a 1.
If B is b/w A, C, then B can have a 0 or a 1 there.
![4cded4eb.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/4cded4eb.png =300x)
- 0:
- A^B < A^C
- A^B < B^C
- (both conditions are important)
- 1:
- B^C < A^B
- B^C < A^C
In both cases, the min xor is b/w consecutive elements, and not b/w extremes.
Solution: Sort. Find xor of consecutive pairs. Return min.
O(n log n)
-- --
Google Code Jam '19
-------------------
> Given master server with N slaves.
> user inputs binary string of length N
> send each bit to one server
> to read back, master asks slaves
> slaves are faulty, can go down, and don't return anything
>
> ![56cbd86d.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/56cbd86d.png =300x)
>
> input: 1010.
> slaves 2, 4 go down
> read: 11
>
> input: 1111
> slaves 2, 4 go down
> read: 11
>
> Find out all faulty slaves by minimizing number of input queries
>
**Brute Force:** O(n). Check each slave one by one by setting just one bit each time
**Optimized:**
- we send several strings. Represented as matrix
- If ith slave is faulty, then ith column is dropped off.
- Say 2, 3 are faulty
- ![47132572.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/47132572.png =300x)
- simply encode each slave number in each column and send
- ![5c782630.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/5c782630.png =200x)
- whatever comes back are columnwise numbers of active slaves
- ![9e762159.png](:storage/e8857c4d-a2f9-4142-91cb-4eb909379fd2/9e762159.png =400x)
Instead of sending N strings, we send strings of length N
We only need $\log_2 N$ strings
So, for $10^9$ slaves, I only need 32 queries!
-- --
Sum of Hamming Distances
------------------------
> Given A[N], find sum of Hamming distance b/w each pair of elements.
> x = 0110
> y = 1001
> d = 1111
>
**Brute Force:** All pairs $O(n^2)$
**Optimized:**
For each bit:
count with bit set = x
count with bit not set = y
contribution of bit = 2^bit * x * y
sum up
**O(32 * n)**
Remember the pattern? Instead of summing up all submatrix, we counted contribution of each cell. Reverse Lookup
-- --
following Kshitij's lecture

View File

@@ -0,0 +1,166 @@
Graphs 1
--------
G = (V, E)
- directed / undirected
- edge describes some relationship
- edge can have value - which can be some property of that relationship
- edit distance of pan --- pen is 1
- bi-directional: a->b implies b->a
- weighted/unweighted - when 1 property associated with edge - some number
- when all weights are same, we don't represent the weights
- ask students for examples of undirected graphs (fb friends) and directed (twitter follows / company hierarchy) and weighted graphs (city distances)
Trees vs graphs
- exactly 1 path b/w any pair of nodes in a tree
- because acyclic. If 2 paths, cycle occurs A-B-A or A-x-B-x
Simple graph
- no self loops
- no multiple edges b/w any 2 nodes
- max edges = $n \choose 2$
- such is a clique $K_{n}$
Disconnected vs Connected
connected = can go from any node to any node
a b c
a-b c
a-b-c
a-b
\c/
Connected Components
largest subgraphs which are connected
connected graph has exactly 1 connected component
directed needs strong connections to be connected
a->b is not connected
-- --
Representations
---------------
Adjacency Matrix
----------------
does path exist?
for undirected, $A$ is symmetric across the major diagonal.
Diagonal is 0 for a simple graph
Space: $O(n^2)$
Checking edge: $O(1)$
Can puts weights/cost/distance as well.
$A^n_{ij} =$ number of $k$ length walks b/w $i, j$
Adjacency List
--------------
List of lists
Space: efficient for sparse graphs
Time: $O(n)$ lookup in the worst case
$O(1)$ degree count in worst case
better if we only want to list down the neighbors
-- --
Traversals
----------
- same as for trees, just remember visited to prevent infinite loops
- start from any node - because no root
- tree defined using graph - rooted, unrooted
- BFS - $O(|V| + |E|)$
DFS using stack
- remember to keep the count of children explored and the parent, so that we can resume exploring from the next child
Check Connected
---------------
undirected - just run DFS from 1. If all visited, connected
DFS over disconnected graph - must start from all nodes one by one
BFS -
![dc2d0b12.png](:storage/30547dac-c72e-46b3-86e3-479b31df3a42/dc2d0b12.png)
start from some node.
levels, min distance from that node
BFS for single source shortest path, when edge weights are EQUAL
Doesn't work when a-b-c < a-c
-- --
Undirected graph with weights 1 or 2
Can still NOT apply BFS
-- --
pseudo/dummy nodes
- can't always create if weights are large
- how to add them virtually? counter - inefficient
- heap - efficient
-- --
![93c9f38f.png](:storage/30547dac-c72e-46b3-86e3-479b31df3a42/93c9f38f.png)
1 = land, 0 = water
find the number of islands
diagonals allowed
find the number of connected components via DFS
![5c8b1184.png](:storage/30547dac-c72e-46b3-86e3-479b31df3a42/5c8b1184.png)
-- --
grid with 0s and 1s
capture all 0s surrounded by 1s on all 4 sides
![6f39934a.png](:storage/30547dac-c72e-46b3-86e3-479b31df3a42/6f39934a.png)
apply DFS to find components of 0s
if reaches boundary, don't capture
if not, we've surrounded, capture all
-- --
reach from source to destination
![151b8e6a.png](:storage/30547dac-c72e-46b3-86e3-479b31df3a42/151b8e6a.png)
-- --
shortest distance of all 0s from any 1
![f8a8702a.png](:storage/30547dac-c72e-46b3-86e3-479b31df3a42/f8a8702a.png)
BFS from all 1s
inspire from 1 and 2 bombs
![ad3d4993.png](:storage/30547dac-c72e-46b3-86e3-479b31df3a42/ad3d4993.png)
-- --
any shortest distance?
BFS from all 0s
or prev and find min

View File

@@ -0,0 +1,180 @@
Greedy
------
$k$ negations
-------------
> Given A[N]
> can have -ve can have 0s
> k negations
> can choose same element multiple times
> find the maximum sum that you can achieve
always find the smallest and negate it
Sort: $O(n \log n + k)$
Min Heap: $O(n+k \log n)$
Note: 1 2 will have -1 2 or 1 2 as the final answer
can keep toggling the smallest element
-- --
What is Greedy
--------------
Greedy - when optimal solution to a local problem is also the optimal solution to the global problem
That is, if you can act greedily at every step, and still reach the optimal.
If you don't have to think long term to achieve the optimal
-- --
Where will greedy not work?
---------------------------
![65112ffa.png](:storage/8d511c68-5ee9-423f-b945-bf7407cdb509/65112ffa.png)
Local solution is not contributing to the global solution
Whenever greedy works, it will be based on observations and intuition
But have to be careful because can be subtle-non-greedy case
-- --
Max Sum Subset
--------------
> Given A[N] with -ves
> Find the subset of size k with maximum sum
>
Sort and take top k values
$O(n \log n)$
-- --
Amazon - Min Subset Product
----------------------------
> Given A[N]
> min possible subset product
>
Examples
> -1 -1 -2 4 5 = -24
> -1 0 2 = -2
> 0 1 = 0
>
1. If no -ve, then choose min $\geq 0$
2. If k -ve, then choose all $> 0$. don't choose 0
- if odd -ve, choose all
- if even -ve, choose the smallest odd -ves
$O(n)$
-- --
Activity Selection
------------------
Multiple companies. Very important
> ![96706e2d.png](:storage/8d511c68-5ee9-423f-b945-bf7407cdb509/96706e2d.png)
> max no of activity that can be performed without overlapps
**Incorrect:** min sized?
```
============= ===============
========
```
**Incorrect:** start time
**Correct:** least overlaps?
**but easier:** first one to end
sort by end time and execute
**Proof:**
Assume there exists a solution that doesn't include the min end time job.
Add this job. Either it overlaps with 1, or with 0.
Optimal in both cases
So, for every optimal solution without the min end job, we also have an optimal solution with the min end job.
So, optimal to always choose the min end job
![8d6e9fbb.png](:storage/8d511c68-5ee9-423f-b945-bf7407cdb509/8d6e9fbb.png)
-- --
Flights
-------
> start, end time of flights
> num of platforms
>
+1 -1, prefix sum max
![03c1d903.png](:storage/8d511c68-5ee9-423f-b945-bf7407cdb509/03c1d903.png)
-- --
Job Scheduling + Profit
-----------------------
> day deadlines for jobs
> can perform only 1 job per day
delay the job
$O(n \log n + n^2)$
$n \log n$ to sort by profit
$n^2$ because start at end time and move left to find an empty slot
Can reduce to n log n using BBST
we want the highest number in the set which is less than x
we also want to remove any given number from set
set - upperbound - google
-- --
Rats and Holes
--------------
> Rats
> Holes
> equal count
> locations given for each
> ech rat runs together
> each must reach a hole
> max time so that all reach hole
>
sort, all go left or all go right
cant cross because that will increase time
```
------- ----------
vs
----------
---------------------------
```

View File

@@ -0,0 +1,80 @@
LLD 1
-----
- **What is the Lowest Level?**
- Code
- Not feasible to communicate at this level
- Large systems can have hundreds of thousands of LOC
- if the interviewer asks you to design amazon, he doesn't expect you to write code. He first expects the HLD/LLD
- **High Level Design**
- very high level view
- still allows you to see that there are some components and the way things operate
- **Low level design**
- closer look, but still higher than code.
- behavior / skeleton, not implementation
-- --
Example
-------
Website - webpage, application code, DB
Fetch data, persist
**HLD**
- ![186867fa.png](:storage/f62e8f9f-4c32-453b-95d6-8e01da320ef2/186867fa.png =400x)
- doesn't worry about how the data is fetched, what the DB schema is, what tables exist, what the tech stack is
**LLD**
- not the actual code. Higher level than code
- Consider a function that adds two numbers
```python
def add(a: int, b: int) -> int: ...
```
LLD just tells you that the function takes 2 args and returns the sum. Doesn't bother about the actual implementation
- LLD talks about entities (classes), their interactions, and their properties (attributes) and behavior (functions)
-- --
**Procedural Code**
- top-down
- no obvious segregation of responsibility
- no one-to-one mapping to real world entities
**Object Oriented**
- map any real world entity to a code entity (class)
- list down the properties/attributes of each entity
- list down the actions/behavior/methods of each entity
- list down the interactions b/w various entities
-- --
Example:
Template / Blueprint for a Bird
-------------------------------
```python
class Bird:
weight: float
height: float
color: Color
def fly(): ...
```
This template does not signify one particular bird. It describes a class of a Bird.
A specific bird will be represented by an instance of this class.
-- --
Constructing an instance / object
---------------------------------
- invoke the constructor of the class
-
- ```python
```

View File

@@ -0,0 +1,295 @@
LLD 2
-----
- Do you understand what a class is?
- Why we use OOP
- What an object is?
- an instance of a class.
- a physical entity that has some snapshot of the values of the attributes of the class
-- --
Builder Pattern
---------------
1.
```java
class Bird {
String color
public Bird(String color) {
this.color = color;
}
}
Bird b = new Bird(); // how to create an object
Bird b = new Bird("green"); // how to set attributes initially
```
1. **Now let's say that we wanted to add attributes to the class**
```java
int height, weight;
```
1. **Do we need to change the way we're invoking the constructor?** Because we now want to pass the height and weight too?
```java
public Bird(String color, int height, int weight) {}
```
1. **Now let's say we wanted to add 10 more attributes.** What change would you have to do?
1. Use a longer constructor.
1. **Is that a good idea? What can do wrong with that?**
- constuctor becomes huge
- increases complexity, hence increases errors. Might confuse the order of variables. Might forget to pass some. Might pass incorrect values.
- So, never write a function that takes in so many parameters.
1. **There is an even bigger problem. Identify?**
Backwards compatibility. Existing code breaks!
Explain how with example.
1. **Solution 1**:
- Have multiple constructors
- constructor overloading
- old code continues to use old constructor. New code uses new constructor
1. **Issue?**
Can't choose which attribute to set. Must set all attributes.
1. **Bad Solution 1**
- Make constructor for every possible combination
- how many constructors? $2^n$
- Adding any attribute is a nightmare
1. **Bad solution 2**
- pass an object
```java
public Bird(Attributes obj) {
this.weight = obj.weight;
...
}
```
- same problem now repeated for obj
- So, doesn't help
1. Builder Pattern
```java
public class Bird {
int height, weight;
String color;
// set to private to enforce builder
public Bird(Builder builder) {
// same as bad solution 2, but Builder is special
this.height = builder.height;
this.weight = builder.weight;
this.color = builder.color;
}
// -------------------- Builder --------------------
// explain why static
public static class Builder {
int height, weight;
String color;
public Builder(); // don't pass values in constructor
public Builder setHeight(int height) {
this.height = height;
return this; // explain the return type
}
public Builder setWidth(int width) {
this.width = width;
return this;
}
public Builder setColor(String color) {
this.color = color;
return this;
}
public Bird build() {
// because we need an instance of Bird
// and not an instance of Builder
Bird b = new Bird(this);
return b;
}
}
// --------------------------------------------------
}
Bird b = new Bird.Builder()
.setHeight(10)
.setColor("red")
// can skip some variable - weight
.build();
```
1. Client can now initialize Bird in whatever order, using whatever attributes they want.
1. **What if we now wanted to add an attribute?**
1. Simply put the attribute in class and Builder. Add one line in contructor. Add one method in Builder
1. **Benefits:**
- Simpler to use
- Backwards Compatible
1. This is in Java, C++. Languages like Python have something else.
1. How to now enforce some attribute?
1. Put it in the builder constructor
```java
public Builder(int height) {
this.height = height;
}
```
Client can still change the height later.
1. How to enforce Builder? make Bird constructor private
1. This is called Builder Pattern.
1. Useful for classes with lots of attributes, and whose attribute requirements can be changed.
-- --
Stateful vs Stateless
---------------------
```java
// Stateful
public class Adder {
int a;
int b;
public int add() {
return this.a + this.b;
}
}
Adder a = new Adder(5, 6);
int result = a.add();
// Stateless - draw on RHS
public class Adder {
public static int add(int a, int b) {
return a + b;
}
}
int result = Adder.add(5, 6);
```
- What is better? Stateful or Stateless? todo: -50
- Math.max, System.out - stateless
-- --
Address Validation
------------------
- useful in lots of companies, especially ecommerce sites like amazon
- if while placing an order, if you put the city as Mumbai but the pin as Delhi, will it accept? Should it accept?
- why important - must validate the address before the order is shipped
```java
class Address {
addressLines;
city;
state;
zip;
}
```
- algorithm to validate the address lines would be much different from the one which validates the zip
- zip is only a few chars. Address line can be huge
- Different Class for each.
- Because can have multiple logic depending on country / state
- namespace
- component level validators:
- AddressLinesValidator
- ZipValidator
- SateValidator
- CityValidator
- top level validator:
```java
public class AddressValidator {
public bool validate(Address a) {
return (
AddressLinesValidator.validate(a.addressLines)
&& ZipValidator.validate(a.zip)
&& StateValidator.validate(a.state)
&& CityValidator.validate(a.city)
);
}
}
```
- Let's try to write for a component level validator
```java
public class ZipValidator {
public book validate(String zip) {
// some logic here
}
}
```
How would this be actually implemented?
- Have some DB containing the valid zip codes
- Should the DB call be here?
- DB is on a different server
- Complex connection code. Network call. Caching. Access control.
- Nopes. Single responsibility.
- Have a different class for all DB operations
- Same DB will also have details about cities, states, ...
Singleton Pattern
-----------------
```java
public class ResourceInitializer {
// where do you initialize all the things?
public ResourceInitializer() {
// connect to DB
// query
// parse results
// store data in this.attribute
}
}
```
- What happens if we create a new DB instance for each call?
- repeated expensive connections
- DB will get DOS'd
- Don't want clients to create multiple isntances
- First instance itself will load all the needed data and store it in attributes
- Clients must share one common isntance
- Hide the constructor - private
```java
public class ResourceInitializer {
private static ResourceInitializer INSTANCE;
private ResourceInitializer() {
// connect to DB
// query
// parse results
// store data in this.attribute
}
public static ResourceInitializer getInstance() {
if(INSTANCE == null) {
INSTANCE = new ResourceInitializer();
}
return INSTANCE;
}
}
```
- now, clients can't access contructor.
- they must call getInstance to get an instance
- same instance shared across all clients
- now it can have attributes that can be initalized in constructor
```java
public Set<String> zips;
private ResourceInitializer() {
// init zips
}
ZipValidator {
bool validateZip(String zip) {
return ResourceInitializer.getInstance().zips.contains(zip);
}
}
```
- this code saves lot of resources and time
-- --

View File

@@ -0,0 +1,219 @@
LLD 3
-----
Factory Pattern
---------------
1. Trying to validate address
```java
class Address {
String country, state, city, []addressLines, zip;
}
```
1. Algorithm for validating address will differ from country to country.
1. Different countries have different breakups.
- Some countries don't have states
- Japan has provinces
- Some European countries have counties
- Meaning of state could be different
- Could have different ways of writing the addresses
- US addresses are more structured
- Indian addresses have lots of different ways - c/o xyz
- Chinese people write addresses in Chinese
1. So, different classes for each country
```java
public class INValidator {
public bool validate(Address a) {}
}
public class USValidator {
public bool validate(Address a) {}
}
```
Now, let's say that I ship these validators as a library
Some client wants to use these validators to validate a random address
```java
public class ClientValidator {
public bool validate(Address a) {
if(a.country == 'India')
return new INValidator().validate(a);
else if(a.country == 'USA')
return new USValidator().validate(a);
...
}
}
```
1. **Is this good?**
- client needs to know the name of the class for each country
- difficult to test
- unknown country - Indonesia. Does a class exist for it?
- IN stands for India or Indonesia?
- could lead to correct addresses being invalidated or wrong addresses be accepted
1. **Pull into interface**
- ![24debe26.png](:storage/e65b85d8-61b9-4991-b67d-d0c285e92bb4/24debe26.png =300x)
- all these classes are multiple forms of the same thing
- interface `Validator`, which asks to implement method `valdiate`
- coding your classes against an interface
1. **Runtime polymorphism**: `Validator v = new INValidator();`
1. **Who should worry about the mapping from country name to Validator?**
- client should not
- I should
- Keep a map
1. Need to create a class whose responsibility is to keep this mapping
```java
class X {
// why private? don't allow client to change this
private static Map<String, Validator> validators;
public X() {
validators.put("USA", USValidator);
validators.put("USA", INValidator);
}
public Validator getValidator(String country) {
// return validators.get(country); - bad
// could lead to null pointer exception
if(validators.has(country))
return validators.get(country);
throw new InvalidCountryException();
}
}
```
1. Too many objects being created in the constructor. Will be used many times. Use Singleton Pattern.
- make constructor private
- create an instance variable
- expose a getinstance function
1. Client code
```java
public class ClientValidator {
public bool validate(Address a) {
return X.getInstance(
.getValidator(a.country)
.validate(a);
}
}
```
1. Client just knows about the interface Validator, and that there's a factory which gives you different implementations of the Validators.
1. Factory Design Pattern
1. Rename X to ValidatorFactory
1. Remember that factories should usually be singleton
1. Notice that we use a pattern that we've already used
1. Usecases -
Gotchas
- don't use this in any language
- Python has dispathcing libraries
- Strategy pattern
- Don't abstract too much
- unless you're a library author
-- --
Stackoverflow
-------------
- Interviewer asks you to implement Stackoverflow
- First step? Start coding?
- **Use Cases**
- Anyone can search and view questions
- Question, answers, comments
- Guest can only search. To add/vote you need to be a member
- Each question can have an active bounty
- Text can contain photos
- User can earn badges
- Admin can blcok users
- Moderator can close questions
- Identify entities - will become classes
- Identify attributes and behavior
- Identify relationships
- ![5d93c037.png](:storage/e65b85d8-61b9-4991-b67d-d0c285e92bb4/5d93c037.png =500x)
```python
class Question:
status: Enum
title: str
description: str
votes: int
def close(): pass
class Comment:
content: stre
votes: int
class Answer:
content: str
votes: int
accepted: bool
```
- ![Screenshot 2019-10-09 at 8.48.21 PM.png](:storage/e65b85d8-61b9-4991-b67d-d0c285e92bb4/0b1d9eeb.png =500x)
```python
class Bounty:
prize: int
expiry: DateTime
def claim(): pass
class Photo:
alt_text: str
url: str
```
- Note where we have composition or not
![f2f50632.png](:storage/e65b85d8-61b9-4991-b67d-d0c285e92bb4/f2f50632.png =600x)
```python
class Member:
age: int
sex: str
def create_question(): pass
class Moderator(Member):
def close_question(): pass
class Admin(Member):
def block_member(): pass
```
- **Direction of arrows.** Member -> Question = Member has instance of Question
- **Composition vs Association**
- ![741698f7.png](:storage/e65b85d8-61b9-4991-b67d-d0c285e92bb4/741698f7.png =400x)
```python
class Account:
password: str
creation_date: DateTime
def delete_account(): pass
```
- Badge
- badges are static
- same badge, multiple people can own
- same person can own multiple badges
- not composition, because deleting either doesn't delete the other
```python
class Badge:
text: str
```
- Search interface
- Guest account - doesn't extend member
- Guest uses search
- ![7b76882f.png](:storage/e65b85d8-61b9-4991-b67d-d0c285e92bb4/7b76882f.png =400x)
Movie Ticket Booking
--------------------
- bookmyticket
- list all the centers of halls - **PVR** (brand), etc
- each **cinema center** can have multiple **halls / audis**
- movie vs movie show (cost, etc)
- hall can run some movie at some time
- each movie can have multiple shows
- search by title, language
- show seating arrangement
- show list of reserved and available seats
- difference b/w the physical chair vs a seat
- pay via cash/card
- no two customers should have the same seat
- discount coupons

View File

@@ -0,0 +1,171 @@
LLD 4
-----
Cascader Pattern
----------------
```java
public class Address {
String city, state, zip, lines[];
}
```
1. Validating address
- Need to validate each part
1. Algo(zip) < Algo(state) < Algo(city) < Algo(lines)
- both in difficulty and time complexity
1. Need to check combined as well
- `* <` Algo(combined)
1. Has been observed that most of the time, people make mistakes in Zip
- Does it make sense to validate everything else?
- No. Check zip first
1. We provide this combined validator to our client
```java
public class CombinedValidator {
private static ZipValidator z = new ZipValidator();
private static StateValidator s = new StateValidator();
bool validate(Address a) {
return z.validate(a)
&& s.validate(a)
&& ...;
// order is important to fail fast
}
}
```
1. Fail fast - prune the bad requests
- just like in recursion - branch and bound
1. Can we improve upon the &&?
- Could be more complex than &&
- Have multiple steps for each validator
1. Abstract it out into a loop
- Find the repeated thing
- Make a loop for it.
1. But class is different each time
- Can we make it same?
- Code classes against an interface
```java
public interface Validator {
bool validate(Address);
}
public class ZipValidator implements Validator {
bool validate(Address a) { ... }
}
```
1. Make the loop (using Runtime Polumorphism)
- What DS should we use to store the Validators?
```java
public class CombinedValidator {
private List<Validator> validators;
public CombinedValidator() {
validators = Arrays.asList(
new ZipValidator(),
new StateValidator(),
...
);
}
bool validate(Address a) {
for(Validator v: validators)
if(!v.validate(a))
return false;
return true;
}
}
```
1. Could we have used a Set instead of List?
- No. Order matters!
1. Clients appear asking for different Combinations
- Either expose the programming interface - clients pass their own lists
- Many times, you onboard a client
- Communication over email / person like "we need to validate xyz using your code"
- You provide them with one function call for that
1. Provide a combination for each client, associated with a client name
- c1 neess V1, V2, V3
- c2 needs V1, V4
- ...
- can use hashmap
- should we store lists in values?
- No, we can use CombinedValidator
1. CombinedValidator can implement Validator
```java
class X {
Map<clientName, Validator> mapping;
public X() {
mapping.put("order_page", CombinedValidator(Arrays.asList(
new ZipValidator(),
new CityValidator(),
new LinesValidator(),
)));
mapping.put("KYC_check", CombinedValidator(Arrays.asList(
new ZipValidator(),
new CityValidator(),
)));
}
}
```
1. Lots of objects being created in constructor. Make it singleton.
1. Convert it into a factory (+singleton)
```java
class ValidatorCascadeFactory {
Map<clientName, Validator> mapping;
private ValidatorCascadeFactory() {
mapping.put("order_page", CombinedValidator(Arrays.asList(
new ZipValidator(),
new CityValidator(),
new LinesValidator(),
)));
mapping.put("KYC_check", CombinedValidator(Arrays.asList(
new ZipValidator(),
new CityValidator(),
)));
}
public CascadeFactory getInstance() // singleton
public Validator getValidator(String clineName) // factory
// note: exception handle in getValidator
}
public class ValidatorCascade implements Validator {
private List<Validator> validators;
public ValidatorCascade(List<Validator> validators);
bool validate(Address a) {
for(Validator v: validators)
if(!v.validate(a))
return false;
return true;
}
}
```
1. Cascade
- staircase
- fail: exit
- pass: move to next step
1. Client Code
```java
class ClientValidator {
bool validate(Address a) {
return ValidatorCascadeFactory.getInstance()
.getValidator(name)
.validate(a);
}
}
```
1. Note that in this code, we used Cascade, Factory, Singleton
1. Order important?
- yes, here
- not always
1. Address cleaning
- clean zip
- clean city
- clean State
- clean lines
1. Need to perform all. All are independent - don't effect one another
1. Can use a Set instead of a List
1. Must use List in substrategy
- first remove ,
- then remove space
- then lowercase
- ...
-- --

View File

@@ -0,0 +1,276 @@
LLD 5
-----
- some have still not submitted the BookMyShow diagram
- So postpone it to next class
- For now, BookMyShow
Hotel Management System
-----------------------
- support booking different room types
- suite
- king size
- delux
- **Entities:**
- booking
- room
- **Relations:**
- booking-room
- room-subclass
- search and book rooms for a guest
- **Entities:**
- search interface
- guest
- who else can use search? We can not only book rooms online. People also visit the frontdesk and book rooms
- **Relationships**
- guest uses search interface
- Receptionist
- Who booked a particular room, say 1004
- **Relation:**
- room booking has multiple guests
- one guest can only bok one room
- cancel a booking
- behavior. no new entity / relation here
- track housekeeping tasks
- **Entities:**
- housekeeing task
- housekeeper
- **Relation:**
- housekeeper can perform * tasks
- customer can ask for room service
- room service is different from house keeping
- don't have to pay for housekeeping
- have to pay for roomservice
- order food/drinks in roomservice
- **Entities:**
- room service
- payment should be supported through various modes
- card
- cash
-- --
How should we start?
- from building
- from brand
```python
class HotelBranch:
name: str
def get_number_of_centers():
def add_location():
class HotelCenter: # actual physical building
location: Address
name: str
def get_rooms():
```
HotelBrand 1 <>----- * HotelBranch
```python
class Room:
room_number: str
room_type: str # or subclass
price: float
is_booked: bool
def check_in():
def check_out():
```
HotelCenter 1 <>----- * Room
-- --
How will you get into your room?
Do you need something?
Each room can have multiple keys, right?
```python
class RoomKey:
id: str
barcode: str
issued_at_date: Date
is_active: bool
```
Room 1 <>----- * Key
-- --
Humans
- guest
- receptionist
- housekeeper
- manager
```python
class Person:
name: str
phone_number: str
email_id: str
class Guest(Person):
def create_booking():
class Receptionist(Person):
def create_booking():
class Housekeeper(Person): # or servant. Or differnt subclasses of servant - cleaner / food server / masseur
def add_service_charge(): # for services they offer
# no def create_booking()
```
Person <--- ext --- Guest
Person <--- ext --- Receptionist
Person <--- ext --- Housekeeper
-- --
How do you track / manage these people?
Account
```python
class Account:
name: str
email: str
password: str
```
Person 1 <>------ 1 Account
-- --
How do you track of your sales?
Booking
What is it that you book? Brand/Hotel/Room?
Room
```python
class Booking:
booking_number: str
start_time: DateTime
end_time: DateTime
status: successfull / failed
def modify():
def cancel():
```
Can there be multiple bookings for a particular room?
- Yes, for different times. All bookings can exist simultaneously
Room 1 ---- * Booking
- Composition or Association?
- If room goes bad - leaking / haunted / something not working
- Would you cancel my booking? No - reassign to a room of the same type
- Association
Room ---> Booking
Booking * ------> 1 Guest
Does not need to be composition, because room can be booked for a friend. Could be though depending on the case
-- --
What does a housekeeper do?
- various housekeeping tasks
```python
class HouseKeepingTask: # or record
description: str
start_time: DateTime
duration: Time
```
HouseKeeper 1 -----> * HouseKeepingTask
Not a composition
HouseKeepingTask * <------ Room
Same room could have multiple tasks that were/need to be done
What if room is destroyed? Should destroy previous tasks?
- no
- but what about foriegn keys?
- keep a note in room saying invalid or something
- depends on requirements
- We will discuss DB schema design later in LLD
-- --
RoomService (not the same as housekeeping)
```python
class FoodService:
class MassageService:
```
HouseKeeper 1 ------- * Service
-- --
Now, each service will need some payment.
Invoice
```python
class InvoiceItem:
amount: float
time: DateTime
```
InvoiceItem 1 ------- 1 Service
Each instance of service associated with each instance of invoiceitem
Or we could make Service objects static
Then, Invoice * ------ 1 Service
InvoiceItem * ------ RoomBooking
Same room can request multiple services
-- --
All invoiceitems associated with an invoice
```python
class Invoice:
```
Do you always charge money all the time? No. at the end
RoomBooking 1 -------> 1 Invoice
InvoiceItem * ------<> 1 Invoice
-- --
Searching
```python
<<interface>> Search:
search_by_room_type()
search_by_floor()
```
have catalogues of rooms and mapping that we need
Who can use this?
Receptionist
**Why is search an interface?**
Because search can be done on various things - users, rooms, tasks ..
So, the common functionality of search is an interface. Then there are several modules that implement that interface
-- --
going forward, we will look at DB schema design for things like this
-- --

View File

@@ -0,0 +1,221 @@
LLD 6
-----
BookMyShow
----------
```python
class CinemaBrand:
name: str
class CinemaCenter:
address: str
'Brand 1 <>---- * Center'
class CinemaHall:
hall_number: int
number_of_seats: int
'Center 1 <>---- * Hall'
# show seat is different from phycial Hall seat
class HallSeat:
location: Location
type: str # delux / normal / ..
# can you book a physical seat?
# note: don't have the price of chair here
# note: don't have is_reserved here
'Hall 1 <>---- * HallSeat'
class Movie:
name: str
director: str
description: str
language: str
class Show:
created_on: Date
start_time: Time
end_time: Time
'Movie 1 <>----- * Show'
'Hall 1 ---- * Show'
class Booking:
number: str
number_of_seats: int
def cancel():
'Booking * ----<> 1 Show'
class ShowSeat:
seat_number: int
is_reserved: bool
'Booking 1 ----- * ShowSeat'
'HallSeat 1 <>----- * ShowSeat'
'Show 1 <>---- * ShowSeat ' # can have. not strictly needed. Depends on usecase
class Payment:
amount: float
trans_id: str
class Coupon:
id: int
amount: float
expiry: Date
'Payment 1 ----- 0-1 Coupon'
'Payment 1 ----- Booking'
class Cash(Payment):
class Card(Payment):
'''
Cash <--ext-- Payment
Card <--ext-- Payment
'''
# first show without inheritance
class Customer(Person):
make_booking()
'Customer 1 ----> Booking'
class Admin(Person):
add_movie()
add_show()
block_show()
'Admin 1 ---- * Show'
'Admin 1 ---- * Movie'
class FrontDesk(Person):
'FrontDesk 1 ---> * Booking'
class Person:
name: str
address: str
email: str
'''
FrontDesk <--ext-- Person
Admin <--ext-- Person
Customer <--ext-- Person
'''
class Account:
id
password
'Account 1 ----<> 1 Person'
class Guest:
# note: doesn't extend person
register()
<<interface>> interface Search:
by_name()
by_language()
'Person ---uses--> search'
'Guest ---uses--> search'
class Catalogue <implements> Search:
movie_titles: {name -> list of movies}
language_titles: {lang -> list of movies}
by_name()
by_language()
```
-- --
Schema Design
-------------
- store everything in one table
- yay \o/
- is this good design?
why store into multiple tables?
-------------------------------
Anomalies:
- college name, rank. Student name. Branch.
- **insert anomaly:** null values when data is not known
- **delete anomaly:** deleting a student causes loss of info about a particular college's rank
- **update anomaly:** updating the rank of a college needs updation of thousands of rows
- Map each entity to a table
- Attributes of entity become the columns of the table
- Define a primary key (could be a single column or a group of column)
- Create a table for each relationship
- Think about if the relationship needs to have some properties or not:
- entities: students, course
- relationship: enrolled
- relationship attributes: enrollment date, marks, type (elective/audit/core)
- add these attribs to the relationship table
- The primary key of the relationship table will be the group of primary key of each of the participants in the relationship. (ex, (user_id, course_id))
- Create foreign key constraints: user_id, course_id
Normalizations
--------------
- 1NF: data should be atomic. Don't store lists of things. Instead, make multiple rows.
- example: languages a student knows.
- now, I need to decide an id, because the previous id might not be able to identify a unique column
- 2NF, 3NF, BCNF: we won't go over them. More in DBMS class
- follow logical thinking, and you will automatically get proper normalization
Over Normalization?
-------------------
- n+1 problem
- need to join the tables to get back the data anyway
-- --
- How to do composition in DB?
- depends. Cascading deleted turned on or not?
- depends on the DB. Different DBs require different things
- some will automatically delete references for you
- some will not
- safe way: setup your DB to not do it automatically. Do it yourself in code
- delete references first
- then delete row
- How to do auto increment in DB?
- null / unique / primary / foreign
```sql
CREATE TABLE Persons (
ID int NOT NULL AUTO_INCREMENT,
UNIQUE (ID),
PRIMARY KEY (ID)
);
CREATE TABLE Objects (
ID int NOT NULL AUTO_INCREMENT,
UNIQUE(ID),
PRIMARY KEY(ID)
);
CREATE TABLE PersonObjects (
PersonID int,
ObjectID int,
FOREIGN KEY (PersonID) REFERENCES Persons(ID),
FOREIGN KEY (ObjectID) REFERENCES Objects(ID),
PRIMARY KEY (PersonID, ObjectID)
)
```
How to do extension? Just create another table
Usually not enforced in DB

View File

@@ -0,0 +1,55 @@
Machine Coding Splitwise
------------------------
Create Splitwise
----------------
- Has everyone used splitwise?
- Social expense management app
- Simplifies bookkeeping amongst groups
- start coding? yay? \o/
- no. Requirements first
Requirements
------------
> - A user can add an expense. While adding the expense, the amount can be split amongst any other users
> - Expense can be of 3 types
> - split equally
> - take care of missing money
> - unequal: value
> - unequal: percentage
> - The total expense must add up to 100% (or the total money value)
> - Proper validation must be done for the expense
> - 2 decimals, because currency
> - 2 decimals for % as well
> - Users must have their details
> - Show expenses of user
> - show balance report of all users
> - Show balance report of a user against all users
> - don't show user if s/he has 0 balance against a user
>
Input format
------------
> - record expense
> - who_paid
> - people in the group
> - expense type - equal/exact/percent
> - if expense is unequal - the values
> - show all - current balances
> - show userid - current balance
> - passbook userid - history
> - simplify expenses
>
> a -100-> b
> b -100-> c
>
> a -100-> c
>
Output format
-------------

View File

@@ -0,0 +1,364 @@
Maths 1
-------
Vivek, July EliteX
-- --
pragy@interviewbit.com
Some basic Maths - concepts that are used in coding questions and interviews
Random Functions
----------------
> Given function rand5() defined as follows
```c++
int rand5() {
// return random number from [1..5] with equal probability
}
```
> The implementation of the function is not provided - black box
> Given rand5, implement a `rand7()` that returns a random number from [1..7] with equal probability
>
Try using rand5 to create rand7, and try minimizing the number of calls to rand5
Wrong Approach: call rand5 7 times, add and divide by 5
Why wrong:
```
to get 7, we need 7 5's, so prob = $(1/5)^7$
1 0
2 0.0051
3 0.1523
4 0.5044
5 0.3088
6 0.0294
7 0.0001
```
**1 call:**
- Mapping {1..5} to {1..7}.
- Can't map single number to multiple outputs.
- So, not possible
**2 calls:**
- Mapping {(1,1)..(5,5)} to {1..7}.
- So, we need to map 25 outputs having equal prob, to 7 outputs
- Challenges:
- Map 2d to 1d
- Maintain equal prob
- Instead, think rand6() and rand9()
- now, we have matrix of 6x6. Total 36 possibilities.
- Map to 9 values by making 4 buckets
- ![52f49e08.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/52f49e08.png)
- First buckets contains numbers from 1..9
- Second bucket contains numbers from 10..18
- So, `1 + (x%9)` would work
- Now, how to transform $(x, y)$ to numbers by doing $(x-1) * 6 + y$
```python
def rand9():
x = rand6()
y = rand6()
val = (x - 1) * 6 + y
return 1 + val % 9
def rand9():
return 1 + ((rand6() - 1) * 6 + rand6()) % 9
```
Now, this worked because 36 is divisible by 9
So, for rand7 using rand5, if we make
- 2 calls, make 3 buckets, use 1-21, waste 4
![6270c29c.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/6270c29c.png =300x)
- When discarded, call rand5 again
```python
def rand7():
val = (rand5() - 1) * 5 + rand6()
if val > 21: # discard and redo
return rand7()
return 1 + (val % 7)
```
-- --
GCD
---
gcd(a) = largest $x$, such that $a|x$ and $b|x$
max possible value of $gcd(a, b) = min(a, b)$
**Brute Force**
```
def gcd(a, b):
for i <- 1 .. min(a, b)
if a % i == 0 and b % i == 0:
return i
```
Complexity: $O(\min(a, b))$
**Euclidean algo**
![5b3ffff4.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/5b3ffff4.png)
![5b85a308.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/5b85a308.png)
![55070460.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/55070460.png)
![95ddd25e.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/95ddd25e.png)
Stop if divisor is 1 or remainder is 0
```python
def gcd(a, b):
if a == 0:
return b
return gcd(b % a, a)
```
Complexity: $O(\log_2\max(a, b))$
Why: after one step, max possible value of remainder is $< b/2$
Cases
- $a < b/2$ - remainder $< a$, so remainder $< b/2$
- $a > b/2$ - division eats up more than half, and remainder is less than half
![69762a56.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/69762a56.png)
-- --
GCD of multiple numbers
-----------------------
$gcd(a, b, c) = gcd(c, gcd(a, b))$
Does order matter? No.
Analogy with
- longest common prefix aac, aabc, aabcd
- Set intersection
Whenever we're finding common things, usually order doesn't matter
-- --
> Given A[N]
> Return 1 if there is any subsequence with gcd = 1, else return 0
>
Explain subsequence (can skip) vs subarray (contiguous)
> Example:
> A = 4 6 3 8
> return 1, because 4 3 has gcd 1
> So does 3 8
> and 4 3 8
>
**Brute Force**
Consider all subsequences - $O(2^n)$
**Simple Approach:**
Simply take gcd of the whole array
Why?
If there is any subsequence whose gcd is 1, the gcd of the entire array must also be 1
If the gcd of entire array is 1, then there's some subsequence which causes it
Complexity: $O(n \log \max)$
-- --
> Given number n, find all factors of n
>
Observations:
- largest factor is n itself
- all other factors are $\leq n/2$
So, loop from 1..n/2
Time complexity: $O(n)$
But what about not just factors, what about pairs of factors?
(1,n), (2, n/2), (x, n/x) ..
```python
for(i = 1; i < sqrt(n); i++)
if( n%i == 0 ):
factors.append(i)
factors.append(n/i)
```
Why sqrt? if x = n/x, then $x = \sqrt n$
Complexity: $O(\sqrt n)$
-- --
Even factors?
-------------
**Brute Force**: Loop and count
**Simple:** Check if perfect square. If perfect suqre - odd, else even.
Binary search / newton raphson
-- --
Check Prime
-----------
**Brute Force** Loop from 1 to $\sqrt n$ and check
$O(\sqrt n)$
-- --
Generate all primes till n
--------------------------
Using last approach: $O(n \times \sqrt n)$
**Sieve of Eratosthenes** (era - tos - thenis)
- Assume all prime
- cut 1
- next uncut is prime
- cut all multiples - because can't be prime
- go only till sqrt
![3fa0e7ff.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/3fa0e7ff.png =400x)
Optimizatiopn
- start cutting from $i\times i$, because $i \times (i-1,2..)$ is alreayd cut
```python
primes[N] = {1}
primes[0] <- 0
primes[1] <- 0
for(i = 2; i * i <= N; i++)
if(primes[i] == 1)
for(j = i; i * j <= N; j++)
primes[i*j] = 0
```
Complexity:
2 -> N/2
3 -> N/3
...
$\sqrt N$ -> 1
total = $N (1/1 + 1/2 + ...)$
= $O(n \log n)$
Memory = $O(n)$
Caution: Don't build a sieve if you just want to check one number. $O(\sqrt n)$ vs $O(n \log n)$
Note: better algos exist for primality testing
-- --
Prime Factorization
-------------------
> $24 = 2^3 \cdot 3$
> Factorize N
```python
p_factors = []
for f <- 1.. sqrt(n)
while n % f == 0
p_factors.append(f)
n /= f
```
Issue:
> 404 = 2 * 2 * 101
> our algo gives only 2, 2
> i.e., if a prime factorization contains a prime number that is greater than the sqrt of n. we have an issue
Fixed:
```python
p_factors = []
for f <- 1.. sqrt(n)
while n % f == 0
p_factors.append(f)
n /= f
if n != 1
p_factors.append(n)
```
Time complexity: $O(\log n)$
Inner loop doesn't matter since n is getting decreased
Note: log $O(\log n)$
**Optimization:**
We're going over composite numbers as well. Go over primes only.
But sieve is costly. Ignoring sieve, we will take
O(number of primes < N) time
**Optimization:**
If we can get SmallestPrimeFactor(n) in O(1) time, we can solve in logn time.
Because,
6060 - 2
3030 - 2
1515 - 3
505 - 5
101
Everytime, number if being reduced by atleast half
In sieve itself, we can find the SPF of each number - the first prime to cut that number
Helpful when doing multiple queries
-- --
Number of factors
-----------------
If $\large n = p_1 ^ a p_2 ^ b p_3 ^ c \cdots$
Then number of factors = $(1+p_1)(1+p_2)(1+p_3)\cdots$
-- --
Lecture Bookmarks
```
Lecture Start - 00:23:54
```

View File

@@ -0,0 +1,277 @@
Maths 1 - GCD
-------------
Tushar - fast batch
Kshitij, Sept EliteX
-- --
Some basic Maths - concepts that are used in coding questions and interviews
GCD / HCF
---------
1. gcd(a) = largest $x$, such that $a|x$ and $b|x$
1. GCD examples
- 5, 15 = 5
- 12, 8 = 4
- 8, 16 = 8
- 16, 8 = 8
- 17, 1 = 1
- 12, 1 = 1
- 17, 0 = 17
- 12, 0 = 12
- -5, 0 = 5
1. GCD Properties
- gcd(x, 0) = |x|
- gcd(x, 1) = 1
- does the order matter?
- No
- gcd(x, y) = gcd(y, x) (commutative)
- gcd(x, y, z) = gcd(gcd(x, y), z) = gcd(x, gcd(y, z)) (associative)
- Analogy with
- longest common prefix aac, aabc, aabcd
- Set intersection
- Whenever we're finding common things, usually order doesn't matter
- max possible value of $gcd(a, b) = min(a, b)$ if both a, b are +ve
1. GCD of complete array
- if gcd(x, y) function is given
- simply do pairwise
-- --
Computing GCD
-------------
**Brute Force**
```python
def gcd(a, b):
for i <- 2 .. min(a, b)
if a % i == 0 and b % i == 0:
return i
```
Complexity: $O(\min(a, b))$
-- --
Substraction Approach
---------------------
1. $GCD(a, b) = GCD(a-b, b), \text{if } a > b$
> $GCD(20, 6) = GCD(14, 6)$
**Proof**
1. $a = b + c$
> $20 = 14 + 6$
1. $GCD(a, b) = g$
> $GCD(20, 6) = 2$
1. Thus, $(b+c) | g$ and $b | g$
> $(6+14)|2, 6|2$
1. Thus, $c | g$
> $14|2$
1. Thus, $g = GCD(c, b)$
> $2 = GCD(14, 6)$
1. Hence, $GCD(a, b) = GCD(a-b, b), \text{if } a > b$
So, we can calculate GCD recursively
(Chinese Mathematician)
```python
def gcd(a, b):
if a < b:
a, b = b, a # swap
if b == 0:
return a
return gcd(a-b, b)
```
Time complexity - Worst case linear
but usually much faster
-- --
Euclid Approach
---------------
1. $GCD(a, b) = GCD(b, a\%b), \text{if } a > b$
> $GCD(20, 6) = GCD(2, 6)$
**Proof**
1. $a = k \cdot b + c$
> $20 = 3 \cdot 6 + 2$
1. $GCD(a, b) = g$
> $GCD(20, 6) = 2$
1. Thus, $(k \cdot b + c) | g$ and $b | g$
> $(3 \cdot 6 + 2)|2, 6|2$
1. Thus, $c | g$
> $2|2$
1. Thus, $g = GCD(c, b)$
> $2 = GCD(2, 6)
1. Hence, $GCD(a, b) = GCD(a\%b, b), \text{if } a > b$
So, we can calculate GCD recursively
```python
def gcd(a, b):
if b == 0:
return a
return gcd(b, a%b)
```
**Explain how the numbers are automatically swapped**
![5b3ffff4.png](/users/pragyagarwal/Boostnote/attachments/3312dcc9-9a3d-4d0f-88b3-fa96f86e5a83/772e17f0.png)
![5b85a308.png](/users/pragyagarwal/Boostnote/attachments/3312dcc9-9a3d-4d0f-88b3-fa96f86e5a83/4808ccaa.png)
![55070460.png](/users/pragyagarwal/Boostnote/attachments/3312dcc9-9a3d-4d0f-88b3-fa96f86e5a83/e0af41cd.png)
![95ddd25e.png](/users/pragyagarwal/Boostnote/attachments/3312dcc9-9a3d-4d0f-88b3-fa96f86e5a83/cf4b9112.png)
Stop if divisor is 1 or remainder is 0
Complexity: $O(\log_2\max(a, b))$
Why: after one step, max possible value of remainder is $< a/2$
Cases
- $b < a/2$ - remainder $< b$, so remainder $< a/2$
- $b > a/2$ - division eats up more than half, and remainder is less than half
![69762a56.png](/users/pragyagarwal/Boostnote/attachments/3312dcc9-9a3d-4d0f-88b3-fa96f86e5a83/3bb53b9e.png)
-- --
Array Factorial GCD
-------------------
> Given Array A[N], find the GCD of factorials of elements of array
>
Naive: factorial and then gcd
Solution: min and then factorial
![6f8d9921.png](/users/pragyagarwal/Boostnote/attachments/3312dcc9-9a3d-4d0f-88b3-fa96f86e5a83/6f8d9921.png)
-- --
Array Susequence GCD
--------------------
> Given A[N]
> Return 1 if there is any subsequence with gcd = 1, else return 0
>
Explain subsequence (can skip) vs subarray (contiguous)
> Example:
> A = 4 6 3 8
> return 1, because 4 3 has gcd 1
> So does 3 8
> and 4 3 8
>
**Brute Force**
Consider all subsequences - $O(2^n)$
**Simple Approach:**
Simply take gcd of the whole array
Why?
If there is any subsequence whose gcd is 1, the gcd of the entire array must also be 1
If the gcd of entire array is 1, then there's some subsequence which causes it.
$GCD(\text{array}) = GCD(GCD(A, B, C), GCD(D, E, F, G))$
$= GCD(1, GCD(D, E, F, G))$
$= 1$
Complexity: $O(n \log \max)$
-- --
Delete Elements
---------------
> Given A[N]
> Give me the minimum number of element that you need to delete such that the GCD of the resulting array becomes 1
> If can't, return -1
Same as previous. If 1, then delete nothing.
Else, return -1, because deleting won't help
Side Note: GCD will be 0 only if all the elements are 0
-- --
Delete one
----------
> Given A[N]
> Delete one element, and make the GCD maximum
> 12, 15, 18
> delete 15 to get GCD = 6
>
Naive: $O(n^2)$
Note: deleting min element is not correct
Optimized:
Prefix and postfix GCD
> 12 3 3
> 3 3 18
>
Intuition: Prefix-Sum, postfix-sum to get sum of elements except A[i]
> pre[i-1] + post[i+1] = Sum(A) - A[i]
>
What property enables this? Association & commutative
-- --
Pubg
----
> Given A[N] with healths, minimize the health of the last player
> When a attacks b, we have a, (b-a)
> If health becomes 0, the person dies
>
> 14 2 28 56
> 12 2 28 56
> 12 2 16 56
> 12 0 16 56
>
Note: min is not the answer. Example, 4, 6 An is 2
Observation 1: smaller should attack larger, example 12, 8
So, smallest should attack the rest
untill all become 1 or 0
same as finding the gcd of entire array
-- --
Closed Differences
------------------
> Given A[N], consider any pair $A[i], A[j]$, if the difference $|A[i] - A[j]| \notin A$, append it.
> If no more moves can be made, stop.
> Find the size of the final array
>
$$\frac{\max A}{\rm{gcd} A} + \begin{cases}1 & \text{if } 0 \in A \\ 0 & \text{otherwise} \end{cases}$$
Note: $\max A$ is always divisible by GCD (duh)

View File

@@ -0,0 +1,225 @@
Maths 2 - Factorization
-----------------------
All Factors
-----------
> Given number n, find all factors of n
>
**Observations:**
1. largest factor is n itself
1. all other factors are $\leq n/2$
**Brute Force:**
So, loop from $1 \ldots \frac n 2$
**Time complexity:** $O(n)$
**Observation 3**
Factors come in pairs
(1,n), (2, n/2), (x, n/x) ..
Need to go only till $\sqrt n$
Why sqrt? if x = n/x, then $x = \sqrt n$
```python
for(i = 1; i < sqrt(n); i++)
if( n%i == 0 ):
factors.append(i)
factors.append(n/i)
if( n % i == 0)
factors.append(i) # because i = n/i = sqrt(n)
```
Complexity: $O(\sqrt n)$
-- --
Open Door question
------------------
100 doors, all are closed.
1. Open all doors
2. Close every 2nd door
3. Open every 3rd door
4. Close every 4th door
100. Close every 100th door.
Find the number of doors that are left open.
Approach: Door is toggled by each factor.
Find the number of factors for each 0 <= i <= 100
Check if the number of factors is even or odd.
**How to find if the number of factors is even or odd?**
**Brute Force**: Loop and count
**Observation:** Factors come in pairs. Except for $\sqrt n$
Check if perfect square. If perfect suqre - odd, else even.
Finding $\sqrt n$: Binary search / Newton Raphson
-- --
Check Prime
-----------
**Brute Force** Loop from 1 to $\sqrt n$ and check if the count is 1
$O(\sqrt n)$
-- --
Generate all primes till n
--------------------------
Brute force using $\sqrt n$ check prime: $O(n \times \sqrt n)$
**Sieve of Eratosthenes** (era - tos - thenis)
- Assume all prime
- cut 1
- next uncut is prime
- cut all multiples - because can't be prime
- go only till sqrt
![3fa0e7ff.png](:storage/3d9f53c5-6f21-4ce2-b310-40e38a17113c/3fa0e7ff.png =400x)
Optimizatiopn
- start cutting from $i\times i$, because $i \times (i-1,2..)$ is already cut
- $i$ needs to go only till $sqrt n$
```python
primes[N] = {1}
primes[0] <- 0
primes[1] <- 0
for(i = 2; i * i <= N; i++)
if(primes[i] == 1)
for(j = i; i * j <= N; j++)
primes[i*j] = 0
```
Complexity:
2 -> N/2
3 -> N/3
4 -> O(1)
5 -> N/5
6 -> O(1)
7 -> N/7
8 -> O(1)
9 -> O(1)
...
$\sqrt N$ -> 1 or O(1)
total = $N (1/1 + 1/2 + 1/3 + 1/5 + 1/7...)$
$\Large N \sum_p \frac 1 p$
= $O(n \log \log n)$ ([Mertens' theorems - Wikipedia](https://en.wikipedia.org/wiki/Mertens%27_theorems))
Memory = $O(n)$
Simple Upperbound can be $n \log n$ because $\sum_i \frac 1 i = \Theta(\log n)$ (proof by integration)
Note: better algos exist for primality testing, as well as sieve.
-- --
Caution: Don't build a sieve if you just want to check one number. $O(\sqrt n)$ vs $O(n \log n)$
-- --
Prime Factorization
-------------------
1. find all factors and check if prime
> $24 = 2^3 \cdot 3$
> Factorize N
```python
p_factors = []
for f <- 1.. sqrt(n)
while n % f == 0
p_factors.append(f)
n /= f
```
Issue:
> 404 = 2 * 2 * 101
> our algo gives only 2, 2
> i.e., if a prime factorization contains a prime number that is greater than the sqrt of n. we have an issue
Fixed:
```python
p_factors = []
for f <- 1.. sqrt(n)
while n % f == 0
p_factors.append(f)
n /= f
if n != 1
p_factors.append(n)
```
Time complexity: $O(\sqrt n)$
Inner loop doesn't matter since n is getting decreased
**Optimization 1:**
We're going over composite numbers as well. Go over primes only.
But sieve is costly. Ignoring sieve, we will take
O(number of primes < N) time
**Optimization 2:**
If we can get SmallestPrimeFactor(n) in O(1) time, we can solve in logn time.
Because,
6060 - 2
3030 - 2
1515 - 3
505 - 5
101
Everytime, number if being reduced by atleast half
In sieve itself, we can find the SPF of each number - the first prime to cut that number
Helpful when doing multiple queries
-- --
Number of factors
-----------------
If $\Large n = p_1 ^ a p_2 ^ b p_3 ^ c \cdots$
Then number of factors $= \phi(n) = (1+p_1)(1+p_2)(1+p_3)\cdots$
Sum of factors
$= (1 + p_1 + p_1^2 + \cdots + p_1^a) \cdot (1 + p_2 + p_2^2 + \cdots + p_2^b) \cdots$
$= \Large \frac{p_1^{a+1} - 1}{p_1 - 1} \cdot \frac{p_2^{b+1} - 1}{p_2 - 1} \cdots$
can be found using mod-exponentiation
Product of factors = $n^{\phi(n)}$ where $\phi(n)$ is the number of factors
-- --
https://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n

View File

@@ -0,0 +1,236 @@
Maths 3 - Modular Arithmetic
----------------------------
Arithmetic of Remainders
$x % m$ gives a value $\in [0, m-1]$
Say m = 4
**Property 1 - Modulus repeats**
![97402b22.png](/users/pragyagarwal/Boostnote/attachments/b40d7037-2666-4b31-b623-936a12cc4244/b445a06d.png)
Since 1, 5, 10 have the same modulus, they can be said to be "modular equivalent wrt 5"
$0 \equiv 5 \equiv 10 \mod 5$
$1 \equiv 6 \equiv 11 \mod 5$
-- --
Linearity of remainders
-----------------------
Remainder of sums is the sum of remainders (modular-sum)
**Incorrect:** $(a+b) \% m = a \% m + b \% m$
This is wrong, because (m-1) + (m-1) = (2m-2) can be >= m
**Correct:** $(a+b) \% m = \Bigl ( a \% m + b \% m \Bigr ) \% m$
**Linearity works for both +ve and negative.**
But, we need numbers to be $\in [0, m-1]$
So, negative modulus values can be fixed by simply adding $m$
$(10 - 4) \% 7$
$= (10 \% 7 - 4 \% 7) \% 7$
$= (3 - 4) \% 7$
$= -1 \% 7$
$= -1 + 7$
$= 6$
**Distributive over multiplication, addition, substraction but not division.**
-- --
Count Pairs
-----------
> Given A[N]. non-negative integers.
> Given m
> Count number of pairs (i, j), such that a[i] + a[j] is divisible by m
>
**Brute Force:** $O(n^2)$
Example:
> A = [2 2 1 7 5 3], m = 4
> answer = 5
> (2,2), (1, 7), (1, 3), (7, 5), (5, 3)
**Optimized:**
Instead of thinking of remainders of sum, think of sum of remainders.
That is, if I've an element which gives remainder $x$, then it can be paired with an element which gives remainder $m-x$
![5dd03bec.png](/users/pragyagarwal/Boostnote/attachments/b40d7037-2666-4b31-b623-936a12cc4244/bf41b9e2.png =300x)
Keep counts for each remainder. Finally, count the number of pairs
> 0 - 0
> 1 - 2
> 2 - 2
> 3 - 2
> So, $\dfrac{c_0 (c_0-1)}2 + (c_1 \times c_3) + \dfrac{c_2 (c_2-1)}2$
> $= 0 + 4 + 2 = 6$
>
Special cases for remainders is 0, n/2
Note: loop till m/2 so that you don't double count
```python
total = count[0] choose 2
if m % 2 ==0:
total += count[m/2] choose 2
else:
total += count[m//2] + count[m//2 + 1]
for i <- 1 .. m/2-1:
total += count[i] * count[m-i]
```
Complexity: Time: $O(n + m)$ Space: $O(m)$
-- --
Count Triplets
--------------
> Given A[N] with non-negative integers
> Given m, find the number of triplets such that sum is divisible by m
>
Think in terms of the last question
**Brute Force**: $O(n^3)$
**With last approach:** $O(n + m^2)$
1. Bucket
2. Choose 2 mods: a, b. Third mod c = m - (a+b)
3. Count total
4. All 3 from same bucket - for 0 and m//3
5. 2 from same bucket, one from other bucket
6. all 3 from different buckets
![bb5890c2.png](/users/pragyagarwal/Boostnote/attachments/b40d7037-2666-4b31-b623-936a12cc4244/bb5890c2.png =400x)
So, fix two buckets, so 3rd can be chosen
Enforce two things:
1. i <= j <= k otherwise, repetitions can happen
2. i + j + k = 0 or i + j + k = m
```python
total = 0
for i <- 0 .. m-1:
for j <- i .. m-1:
k = (m - i + j) % m # explain the case when i, j are 0
# explain that this mod should handle -ve
# python. for c++/java, do it yourself
if i == j == k:
total += count[i] choose 3
elif i == j:
total += count[i] choose 2 * count[k]
elif i == k:
total += count[i] choose 2 * count[j]
elif j == k:
total += count[j] choose 2 * count[i]
else:
total += count[i] * count [j] * count[k]
```
Time: $O(n + m^2)$, Space: $O(m)$
-- --
Balanced Paranthesis Count
--------------------------
> Given N pairs of paranthesis
> Find number of distinct balanced paranthesis
>
> meaning of balanced: for every prefix, number of opening braces should be >= number of closing braces
>
Example
> 0 pairs
> 0
>
> 1 pair: ()
> 1
>
> 2 pairs: ()(), (())
> 2
>
> 3 pairs: ()()(), ()(()), (())(), (()()), ((()))
> 5
Say we want to construct for n = 3
Choose how many pairs must go inside
![33f72a14.png](/users/pragyagarwal/Boostnote/attachments/b40d7037-2666-4b31-b623-936a12cc4244/33f72a14.png =400x)
![962dd530.png](/users/pragyagarwal/Boostnote/attachments/b40d7037-2666-4b31-b623-936a12cc4244/962dd530.png =300x)
$C_0 = 1$
$C_n = C_0 C_{n-1} + C_1 C_{n-2} + \cdots C_{n-1}C_0$
$\displaystyle C_n = \sum\limits_{i=0}^{n-1} C_i C_{n-i-1}$
-- --
Catalan numbers
---------------
Same as above
Time to find nth catlan number = $O(n^2)$ (because we need to compute numbers before it)
-- --
Number of Paths
---------------
> Given $m \times n$ grid, find the number of paths from (0,0) to (m-1, n-1)
> Can only move right and down.
Approach:
- Every path will have exactly (n-1) right steps, and (m-1) down steps.
- Only the order differs
So, $\dfrac{(n+m-2)!}{(n-1)! \cdot (m-1)!}$
Complexity? O(n+m)
-- --
Number of lower triangle paths in Square Matrix
-----------------------------------------------
> Given $n \times n$ (square) grid, find the number of paths from (0,0) to (m-1, n-1)
> Can only move right and down.
> Exists only in teh lower triangle
>
- First move must be down
- Number of Rs < Number of Ds at every step
Same as balanced parans
![7c611269.png](/users/pragyagarwal/Boostnote/attachments/b40d7037-2666-4b31-b623-936a12cc4244/7c611269.png)
$C_{n-1}$, because n-1 pairs of moves for $n \times n$ matrix

View File

@@ -0,0 +1,143 @@
Psych Coding 1
--------------
Base Setup
----------
1. Create free account on Heroku
1. Install Heroku CLI https://devcenter.heroku.com/articles/getting-started-with-java#set-up
1. Install PostgreSQL https://www.postgresql.org/download/
```bash
brew install postgres
sudo chown -R `whoami` /usr/local
```
1. Ensure postgres is started automatically on boot
```bash
pg_ctl -D /usr/local/var/postgres start && brew services start postgresql
postgres -V
```
3. Create new Idea Project
1. Spring Initializer
1.
+ SDK 11 or 13
+ com.psych.game
+ Scaler Backend Project - Psych
+ Java 11
+ Maven
1.
+ Spring Boot Dev Tools
+ Lombok
+ Spring Web
+ Rest Repositories
+ Spring Web Services
+ Spring Data JPA
+ PostgreSQL Driver
1. name: pragypsych
-- --
Hello World
-----------
1. Create File: devtest.HelloController
```java
package com.psych.game.devtest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/dev-test")
public class HelloController {
@GetMapping("/")
public String hello() {
return "Hello, World!";
}
}
```
1. Try Build & Run
- Build succeeds
- Run fails: Because No DB
1. Run postgres
```bash
psql postgres
\du # display users
\list # list databases
create database psych_local;
\connect psych_local # connect to specific DB
\dt # display tables in current DB
# psql postgres -U pragyagarwal
```
1. Add psych_local DB to IntelliJ
1. Create application.properties
```java
spring.datasource.url=jdbc:postgresql://localhost:5432/psych_local
spring.jpa.hibernate.ddl-auto=update
```
1. Run again. Go to http://localhost:8080/dev-test/
-- --
Deploy on Heroku
----------------
1. Create new project.
```bash
heroku create pragy-psych
```
1. goto https://pragy-psych.herokuapp.com/ to find nothing
1. add git
```bash
git init
git add .
git commit -m "Init"
```
1. add heroku remote
```bash
git remote add heroku https://git.heroku.com/pragy-psych.git
```
1. Deploy
```bash
git push heroku master
```
1. Error: Push Rejected - invalid target release: 11
1. Create **system.properties**
```java
java.runtime.version=11
```
1. Add, commit & deploy
1. Goto https://pragy-psych.herokuapp.com/dev-test/
1. Goto https://dashboard.heroku.com/apps/pragy-psych to see your stuff
1. Note: it auto adds postgres free account
1. See the logs
```bash
heroku logs --tail
```
-- --
Make the models
---------------
-- --
Test
----
https://pragy-psych.herokuapp.com/dev-test/
https://pragy-psych.herokuapp.com/dev-test/questions
https://pragy-psych.herokuapp.com/dev-test/populate
-- --
Post Lecture
------------
Restore
[Google Docs create and edit documents online, for free.](https://docs.google.com/document/d/1J1t-TFA-aw9ZS89LI4guAJ-muJeGTQ_BQB6Fan-zrk4/edit#)
[YouTube](https://www.youtube.com/watch?v=8cSYhtKzlhE)

View File

@@ -0,0 +1,222 @@
Queues
------
- preserves order - FIFO
- queue of people in front of a ticker place
**Operations:**
stack: push and pop, peek
queue:
- enqueue / pushfront
- dequeue / popfront / removefront
- front
- can't be done efficiently with just enqueue and dequeue
- note: dequeue != deque. DEQue stands for Double Ended Queue
-- --
Binary Numbers
--------------
> Generate all binary numbers upto $d$ digits.
- Keep 2 queues
- print 0
- Start with [1]
- pop and print
- append both 0 and 1 to it, and append to queue
- how to append to number? $\displaystyle x = 10x + 0, 10x + 1$
```
0
1
10 11
11 100 101
100 101 110 111
...
```
K-ary numbers
-------------
> Given N
> Print first N positive numbers, whose digits are either 1, 2, 3
>
> output: 1 2 3 11 12 13 21 22 23 31 ...
-- --
Some Tree:
```
1 2 3
11 12 13 21 22 23 31 32 33
```
- BFS: level order traversal: Queue
- DFS: stack
-- --
Implementations
---------------
**Queue using Array**
- front pointer
- read pointer
- enqueue: insert after rear. increment rear
- dequeue: return front. increment front
- issue: wasted space
- empty space, but overflow
- can be fixed by using a circular queue
**Queue using Stacks**
- enqueue: push $O(1)$
- dequeue: pop all into auxillary. pop and return top of auxillary. push all back again $O(n)$
What is we want dequeue to be fast, but enqueue can be slow?
- enqueue: pop all into auxillary stack. Push x. Pop and push all into original
- dequeue: pop
**Stack using Queue**
- push: enqueue $O(1)$
- pop: dequeue all into auxillary queue. Make sure you don't dequeue last element. Copy back values $O(n)$
Similarly, complexities can be reversed here too
-- --
Circular Queue using Array:
---------------------------
```
1 2 3 4 _ _
dequeue 3 times
enqueue 5, 6, 7
Failure, even though empty place is available
```
- Draw it circularly
- use mod with size to keep track of front and rear
```python
def __init__(N):
N
front = rear = -1
def enqueue(x):
if (rear + 1) % N == front:
raise Overflow
elif front == -1:
front, rear = 0, 0
queue[rear] = x
else:
rear = (rear + 1) % N
queue[rear] = x
def dequeue(self):
if front == -1:
raise Underflow
elif front == rear:
x = queue[front]
front, rear = -1, -1
return x
else:
x = queue[front]
front = (front + 1) % N
return x
```
-- --
Doubly Ended Queue
------------------
- insert_front
- insert_last
- delete_front
- delete_last
Standard implementations in all languages (usually circular and array)
Just google and use.
- use array implementation vs linked list implementation
- array
- space efficient
- cache - locality of reference
- can't increase size easily
- vector
- amortized O(1) if double
- linked list
- can increase size easily
- space inefficient
- easier to distribute over multiple machines
-- --
Window Max
----------
> Given A[n]
> Given $k$
> Find max element for every $k$ size window
**Naive**
Keep window of size $k$. Calculate max every time.
$O(nk)$
**Optimized**
Given
```
9 1 3 2 8 6 3 ...
```
window of size 6
- The 8 doesn't allow windows after 9 to have other maxes. So max can't be 1, 3, 2
- So we need to maintain the useful (decreasing) elements
- Read array from left to write and maintain the decreasing elements. So we need push_front
- But when some element in the window becomes useless, pop it from the left. So we need remove_last
- So we can use deque
```
N = 9, k = 3
10 1 2 9 7 6 5 11 3
\------------/
```
- first element of the useful elements is the max.
- pop from last if the element cant be part of next window. So, store indexes
$O(n)$
**Variation**
output max + min for every window of size k

View File

@@ -0,0 +1,230 @@
Recursion & Backtracking
------------------------
Recursion - function calling itself
- initial call from some external function
- recursive calls
- base case
```python
def fib(n):
if n <= 1 : return n # base case
return fub(n-1) + fib(n-2) # recursive calls
fib(10) # initial call
```
-- --
Power
-----
> Given n, k, find $n^k$
>
```python
def pow(n, k):
if k == 0: return 1
nk = pow(n, k//2)
if k % 2 == 0:
return nk * nk
else:
return nk * nk * n
```
why not f(n, k//2) * f(n, k//2+1) in the else condition? To allow reuse of answers
```
19 -> 9 -> 4 -> 2 -> 1 -> 0
19 -> 9 -> 4 -> 2 -> 1
-> 5 -|2
-> 3 -|1
-|2
-> 10 -|5
```
Complexity (assuming all multiplications are O(1))? $O(\log_2 k)$
Break it into 3 parts? k//3 and take care of mod1 and mod2
Binary is still better, just like in binary search
-- --
All Subsets
-----------
> Given A[N], print all subsets
>
Number of subsets? $2^n$
Two choices for each element
One of them is the empty set
Explain that we want combinations, and not permutations. [1, 4] = [4, 1]
Number of permutations will be much larger
```python
def subsets(A, i, aux):
if i == len(A):
print(aux)
return
take = subsets(A, i+1, aux + [A[i]])
no_take = subsets(A, i+1, aux)
```
Draw recursion Tree
How many leaves? $2^n$ - one for each subset
How many total nodes? $2^{n+1} - 1$
Complexity? $O(2^n)$
-- --
Subsets using Iteration
-----------------------
Look at recursion Tree. Going left = 0
Going right = 1
Basically, for each element, choose = 1, skip = 0
So, generate numbers from 0 to $2^n-1$ and look at the bits of the numbers. Each subset is formed using each number
-- --
Lexicographic subsets
---------------------
Explain lexicographic order
```
[]
[0]
[0, 1]
[0, 1, 2]
[0, 1, 2, 3]
[0, 1, 3]
[0, 2]
[0, 2, 3]
[0, 3]
[1]
[1, 2]
[1, 2, 3]
[1, 3]
[2]
[2, 3]
[3]
```
Basically, we're doing DFS. Print when encountering node
But don't print when going left - because already printed in parent
```python
def subsets(A, i, aux, p):
if p: print(aux)
if i == len(A):
return
take = subsets(A, i+1, aux + [A[i]], True)
no_take = subsets(A, i+1, aux, False)
```
time: $O(2^n)$
Space: $O(n^2)$, because we're creating new aux arrays
-- --
Backtracking
------------
- do
- recurse
- undo
Can help reduce the space complexity, because we're reusing the same storage
-- --
Deduplicated subsets
--------------------
> A = [1, 1, 2, 3, 4, 5, 5]
> find all distinct subsets
>
- create multiset
- if A[i] occurs k times, we have (k+1) choices. 0 times, 1 times, 2 times, ... k times
- move on to A[i+1]
-- --
Number of subsets with given sum
--------------------------------
> Given A[N], k find number of subsets with sum k
>
```python
def knapsack(A, k, i, total):
if i == len(A):
if total == k: return 1
else: return 0
take = knapsack(A, k, i+1, total + A[i])
skip = knapsack(A, k, i+1, total)
return take + skip
```
Why can't terminate earlier whne total is good? Because can have -ves and don't consider future sums
k = 6
1, 2, 3 is good, but
1, 2, 3, -1, 1 is also good
-- --
Subsets with sum k (repetitions allowed)
----------------------------------------
> Given A[n]. Only +ves
> Given k
> allowed repetitions
> Find number of subsets with repitions with sum k
>
Solution:
```python
def foo(A, k, i, total):
if i == len(A):
if total == k:
return 1
else:
return 0
if total > k:
return 0
no_take = foo(A, k, i+1, total)
take = foo(A, k, i, total+a[i]) # don't change index
```
Take care of base cases
No negatives allowed, so can check on both array length and total
-- --
following May EliteX by Vivek
3rd October - remedial class - june+may - elite+super

View File

@@ -0,0 +1,308 @@
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
![e777e692.png](:storage/b3ce81fe-2514-47db-9c8f-6e5d3b0dd2aa/e777e692.png =350x)
Can essentially be achieved by swapping
![14bdca46.png](:storage/1d31a4b8-2ef8-4299-8673-f3b477ed5dec/812b8234.png)
```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
-----------------------------------------------
![255b5284.png](:storage/b3ce81fe-2514-47db-9c8f-6e5d3b0dd2aa/255b5284.png =400x)
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, '')
```

View File

@@ -0,0 +1,114 @@
Segment Trees
-------------
Have ever used segment tree? Implemented?
Rarely asked in interviews, but good to know from a competitive programming perspective.
We will cover basics today, and delve into more complex stuff later on.
Has range queries and update queries.
-- --
> Given array (has -ve, has duplicates, unsorted)
> 1 2 -3 3 4 7 4 6
> Given multiple queries that ask the sum from $a_i$ to $a_j$
Brute Force: O(n) per query
Solve using prefix sum. Preprocessing: O(n), query: O(1)
> Now, we also have update queries like - change $a_4$ to 7
- Prefix sum:
+ Query: O(1)
+ Update: O(n) because we gotta change entire prefix sum
- Normal:
+ Query: O(n)
+ Update: O(1)
- Can we do it in $O(\log n)$ time for each query?
What comes to your mind when we talk about $O(\log n)$ time?
![8fd0176c.png](:storage/d9e5e2af-8dad-435c-b0f0-729fca3448fd/31b63f54.png)
- Discarding part of the search space
![45bdcdc1.png](:storage/d9e5e2af-8dad-435c-b0f0-729fca3448fd/45bdcdc1.png)
-- --
Segment Tree
------------
- ![e3eb808f.png](:storage/d9e5e2af-8dad-435c-b0f0-729fca3448fd/e3eb808f.png)
- ![8598c257.png](:storage/d9e5e2af-8dad-435c-b0f0-729fca3448fd/8598c257.png)
+ Update: $O(\log n)$
+ ![27ac5aa0.png](:storage/d9e5e2af-8dad-435c-b0f0-729fca3448fd/27ac5aa0.png)
+ Query: $O(\log n)$
+ if query completely overlaps node range: return entire node value
+ if no overlap at all: return null
+ if some overlap: recurse on both children and apply operation
- worst case: 4 * n because left and right and attached right and left
- Operation must be Associative
-- --
Build Segment Tree
------------------
```python
data = [...] # N
tree = [...] # 4N # 2N-1 - N leaves and N-1 elems in parents
left = lambda n: 2 * n + 1
right = lambda n: 2 * n + 2
def build(start, end, pos):
if start == end:
tree[pos] = data[start]
return
# post order traversal
mid = (start + end) // 2
build(start, mid, left(pos))
build(mid+1, end, right(pos))
tree[pos] = tree[left(pos)] + tree[right(pos)]
build(0, N-1, 0)
```
Note: Always implement it as a class. Do NOT couple your algorithm with your DS.
Okay for Competitive Coding. Reject in interviews.
O(n), because you visit each node only once.
Query
--------------------------
```python
def query(q_start, q_end, r_start, r_end, pos):
if q_start <=r_start <= r_end <= q_end:
return tree[pos]
if r_end < q_start or r_start > q_end:
return 0
mid = (r_start + r_end) // 2
left = query(q_start, q_end, r_start, mid, left(pos))
right = query(q_start, q_end, mid+1, r_end, right(pos))
return left + right
```
Updating
--------
Simple - just change the values from node up to the root - recursive,y come down to the node, update and update each sum
Complexity for query and update: $O(\log n)$, because height of tree is $O(\log n)$
-- --

View File

@@ -0,0 +1,134 @@
Segment Trees 2
---------------
Max and 2nd Max
---------------
store both.
to combine, find max and 2nd max of 4 number
-- --
> n processes start, end
> 1 processor
> find out if a new process can be added
sort and binary search
> n processes start, end
> 4 processors
> find out if a new process can be added
allocate processes to processors and then previous approach
> n processes start, end
> k processors
> find out if a new process can be added
+1 -1 trick
prefix sum
max range query segment tree over the prefix sum
-- --
Flip Bits
---------
> Given series of coin flips
> 0 1 0 1 1 0 0 1
> Given a range, find the number of heads
> Also, given a index, flip the coin at that index
>
Simple, just use Segment Tree
-- --
Bob and Queries
--------
> start A[n] = [0, 0, 0, ...]
> 3 types of queries
> 1. a[i] = 2 * a[i] + 1
> 2. a[i] = a[i] // 2
> 3. sum of counts of set bits in the range s, e
>
observation: numbers will always be 0, 1, 11, 111, ... in binary
can never reach a non-0 even number
so can just keep count of set bits
1. increase a leaf value
2. decrease a leaf value
3. normal seg tree range query
-- --
Powers of 3
-----------
> binary string
> 1. l, r: print value of binary string l to r mod 3
> 2. i: flip the bit at index i
- store the bit in leaf
- combine two nodes $= (2^x\cdot l + r) \mod 3$
![aa19c149.png](:storage/142c3fe6-1d20-4d84-8ee9-51c8f2751685/aa19c149.png)
![21e3e2c1.png](:storage/142c3fe6-1d20-4d84-8ee9-51c8f2751685/21e3e2c1.png)
-- --
> Given ranges in hours from 0 - 24, mark then in your schedule
> For every marker you place, also output how many overlapping tasks
>
todo
- build a tree from 0 - 24
- for each query, update each count
-- --
lazy prop
![ce7714d2.png](:storage/142c3fe6-1d20-4d84-8ee9-51c8f2751685/ce7714d2.png)
lazy tree
- update self. add lazy to children
- always update self from lazy first
-
-- --
~~Optimzed LCA~~
------------
$O(h)$ when we have pointers to nodes
But takes $O(n)$ when we have to search for the nodes
> Binary Tree, No duplicates
> Given multiple keys of type (a, b), find LCAs
> $O(\log n)$ for each query
- Build Euler Path
- Assign index to each node
- Build Min segment Tree
- Keep index of first occurance in a hashmap
todo
- if no duplicates, just store pointers to each node in a hashmap. Then earlier approach (linked list) is still simpler cause no segment tree

View File

@@ -0,0 +1,152 @@
# Sorting
- define sorting: permuting the sequence to enforce order. todo
- brute force: $O(n! \times n)$
Stability
---------
- definition: if two objects have the same value, they must retain their original order after sort
- importance:
- preserving order - values could be orders and chronological order may be important
- sorting tuples - sort on first column, then on second column
-- --
Insertion Sort
--------------
- explain:
- 1st element is sorted
- invariant: for i, the array uptil i-1 is sorted
- take the element at index i, and insert it at correct position
- pseudo code:
```c++
void insertionSort(int arr[], int length) {
int i, j, key;
for (i = 1; i < length; i++) {
key = arr[i];
j = i-1;
while (j >= 0 && arr[j] > key) {
arr[j+1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
```
- **Stablility:** Stable, because swap only when strictly >. Had it been >=, it would be unstable
- **Complexity:** $O(n^2)$
-- --
Bubble Sort
-----------
- explain:
- invariant: last i elements are the largest one and are in correct place.
- why "bubble": largest unsorted element bubbles up - just like bubbles
- pseudo code:
```c++
void bubbleSort(int arr[], int n) {
for (int i = 0; i < n-1; i++)
for (int j = 0; j < n-i-1; j++)
if (arr[j] > arr[j+1])
swap(&arr[j], &arr[j+1]);
}
```
- **Stability:** Stable
- **Complexity:** $O(n^2)$
-- --
Bubble Sort with window of size 3
---------------------------------
- explain bubble sort as window of size 2
- propose window of size 3
- does this work?
- no - even and odd elements are never compared
-- --
Counting Sort
-------------
- explain:
- given array, first find min and max in O(n) time
- create space of O(max-min)
- count the number of elements
- take prefix sum
- constraint: can only be used when the numbers are bounded.
- pseudo code:
```c++
void counting_sort(char arr[]) {
// find min, max
// create output space
// count elements
// take prefix sum
// To make it stable we are operating in reverse order.
for (int i = n-1; i >= 0; i--) {
output[count[arr[i]] - 1] = arr[i];
-- count[arr[i]];
}
}
```
- **Stability:** Stable, if imlpemented correctly
- **Complexity**: $O(n + \max(a[i]))$
- why not just put the element there? if numbers/value, can do. Else, could be objects
-- --
Radix Sort
----------
- sort elements from lowest significant to most significant values
- explain: basically counting sort on each bit / digit
- **Stability:** inherently stable - won't work if unstable
- **complexity:** $O(n \log\max a[i])$
-- --
Partition Array
---------------
> Array of size $n$
> Given $k$, $k <= n$
> Partition array into two parts $A, ||A|| = k$ and $B, ||B|| = n-k$ elements, such that $|\sum A - \sum B|$ is maximized
- Sort and choose smallest k?
- Counterexample
```
1 2 3 4 5
k = 3
bad: {1, 2, 3}, {4, 5}
good: {1, 2}, {3, 4, 5}
```
- choose based on n/2 - because we want the small sum to be smaller, so choose less elements, and the larger sum to be larger, so choose more elements
-- --
Sex-Tuples
----------
> Given A[n], all distinct
> find the count of sex-tuples such that
> $$\frac{a b + c}{d} - e = f$$
> Note: numbers can repeat in the sextuple
- Naive: ${n \choose 6} = O(n^6)$
- Optimization. Rewrite the equation as $ab + c = d(e + f)$
- Now, we only need ${n \choose 3} = O(n^3)$
- Caution: $d \neq 0$
- Once you have array of RHS, sort it in $O(\log n^3)$ time.
- Then for each value of LHS, count using binary search in the sorted array in $\log n$ time.
- Total: $O(n^3 \log n)$
-- --
Anagrams
--------

View File

@@ -0,0 +1,139 @@
# Sorting 2
-- --
Merge Sort
----------
- Divide and Conquer
- didive into 2
- sort individually
- combine the solution
- Merging takes $O(n+m)$ time.
- needs extra space
- code for merging:
```c++
// arr1[n1]
// arr2[n2]
int i = 0, j = 0, k = 0;
// output[n1+n2]
while (i<n1 && j <n2) {
if (arr1[i] <= arr2[j]) // if <, then unstable
output[k++] = arr1[i++];
else
output[k++] = arr2[j++];
}
// only one array can be non-empty
while (i < n1)
output[k++] = arr1[i++];
while (j < n2)
output[k++] = arr2[j++];
```
- stable? Yes
- in-place? No
- Time complexity recurrence: $T(n) = 2T(n/2) + O(n)$
- Solve by Master Theorem.
- Solve by algebra
- Solve by Tree height ($\log n$) * level complexity ($O(n)$)
-- --
Intersection of sorted arrays
-----------------------------
> 2 sorted arrays
> ```
> 1 2 2 3 4 9
> 2 3 3 9 9
>
> intersection: 2 3 9
> ```
- calculate intersection. Report an element only once
- Naive:
- Search each element in the other array. $O(n \log m)$
- Optimied:
- Use merge.
- Ignore unequal.
- Add equal.
- Move pointer ahead till next element
-- --
Merging without extra space
---------------------------
- can use extra time
- if a[i] < b[j], i++
- else: swap put b[i] in place of a[i]. Sorted insert a[i] in b array
- so, $O(n^2)$ time
-- --
Count inversions
---------------
> inversion:
> i < j, but a[i] > a[j] (strict inequalities)
- naive: $O(n^2)$
- Split array into 2.
- Number of inversions = number of inversions in A + B + cross terms
- count the cross inversions by example
- does number of cross inversions change when sub-arrays are permuted?
- no
- can we permute so that it becomes easier to count cross inversions?
- sort both subarrays and count inversions in A, B recursively
- then, merge A and B and during the merge count the number of inversions
- A_i B_j
- if A[i] > B[j], then there are inversions
- num inversions for A[i], B[j] = |A| - i
- intra array inversions? Counted in recursive case.
-- --
Find doubled-inversions
-----------------------
> same as inversion
> just i < j, a[i] > 2 * a[j]
- same as previous. Split and recursilvely count
- while merging, for some b[j], I need to find how many elements in A are greater than 2 * b[j]
- linear search for that, but keep index
- linear search is better than binary search
-- --
Sort n strings of length n each
- $T(n) = 2T(n/2) + O(n^2) = O(n^2)$ is wrong
- $T(n) = 2T(n/2) + O(n) * O(m) = O(nm\log n)$ is correct. Here m = the initial value of n
-- --
> .
>
> I G N O R E
>
> .
Bounded Subarray Sum Count
--------------------------
> given A[N]
> can have -ve
> given lower <= upper
> find numbe of subarrays such that lower <= sum <= upper
- naive: $O(n^2)$ (keep prefix sum to calculate sum in O(1), n^2 loop)
- if only +ve, $O(n\log n)$ using prefix sum
- but what if -ve?
-
-- --

View File

@@ -0,0 +1,300 @@
# Stacks
- who does not know stack?
-- --
Stack
-----
- what are the two most basic operations in a stack?
- peek can be implemented as pop then push same
- Stack is a LIFO datastructure.
- You can only operate on the top
- where have you used stacks?
- undo
- recursion
- pile of stacks
-- --
Quick
-----
- push_bottom a stack using an auxillary stack
- lifo
- reverses when popped
- equivalence with recursion
- anything using a stack can be done using recursion
- draw tree for push_bottom
- how to implement recursion iteratively using stack?
-- --
Stack in recursion?
-------------------
-
- push state of function call before calling a sub-function
- Call stack
- Example
```
def fact(n):
if n <= 1: return 1
return n * fact(n-1)
print(fact(3))
```
- Call stack
```
fact(1)
fact(2)
fact(3)
print
main
```
-- --
What is stackoverflow?
----------------------
- How is memory managed?
- 4 types of memory alloted to a program
```
HEAP
Stack (call stack)
Global / Static Variables
Text / Code
```
- Each memory is fixed. Compiler / JRE / Interpretter takes care of that.
- So stackoverflow is when you have a very deep recursion
- infinite recursion
-- --
Reverse a Stack
---------------
2 auxilarry stacks
```
[1 2 3 4]
[]
[]
[4 3 2 1]
[]
[]
[1 2 3 4]
[4 3 2 1]
[]
[]
```
$O(n)$
**Via recursion:**
```
def reverse(stack):
x = pop()
reverse(stack)
push_bottom(x, stack)
```
$O(n^2)$ time
This uses 2 stacks too, one for recursion, one for push_bottom
-- --
Undo-Redo
---------
- Only undo? 1 stack
- Undo-Redo? 2 stacks
- Example of browser history:
- Click pages, push to undo-stack
- go back, pop from undo-stack and push in redo-stack
- go forward, pop from redo-stack and push in undo-stack
-- --
Evaluating Post-Fix expressions
-------------------------------
- Infix: Inorder
- operator is b/w the operands
- $a + (b*c) / d$
- Postfix: Postorder
- operator is after the operands
- $bc*d/a+$
- Prefix: Preorder
**More examples:**
- infix: $4 * 5 + (2 - (3 * 4)) / 5$
- postfix: $45234*-5/+*$
- can I write it as $34*2- \ldots$ ?
- No, because operation need not be commutative (matrix multiplication)
**Algorithm for Evaluation:**
- go from left to right
- push operands on stack
- when operator, pop top 2 from stack, apply operator, push result
- give example
-- --
Convert Infix $\to$ Postfix
------------------------
> - Convert
> $(1+2) * 3 / (4 - 5) + 6 - 1$
> to
> $21+345-/*61-+$
> - Precedance: `()` > `* /` > `+ -`
> - Can be done in 1 stack
**Algorithm:**
- 4 decisions to make
- what to do when: operand, operator, (, )
- result = []
- stack = []
- operand:
- append to result
- operator:
- if stack has higher precedance (or equal), apply all of them first
```
operator: +
stack:
*
*
-
```
- Applying simply means popping from stack and appending to result
- Don't pop (
- (
- push on stack
- )
- pop from stack until we see (. Pop the ( too
- end
- pop all from stack and append to result
-- --
Google Question
---------------
> N Stock prices for each day
> ```
> A = [100, 80, 60, 70, 60, 75, 85]
> ```
> Longest consecutive sequence ending at $i$ such that the numbers in the sequence <= A[i]
> Do this for all $i$
> Exmple output:
> ```
> input: 100, 80, 60, 70, 60, 75, 85
> output: 1, 1, 1, 2, 1, 4, 6
> include self.
> ```
**Solution:**
- Keep (price, answer) in stack
- traverse array from left to right
- if smaller than stack top price, push (price, 1)
- if larger or equal
- keep popping till larger.
- maintain total answer so far (init by 1)
- once done, push (price, total)
Works because if there was say 59 at the end which would need to stop at 60, it would aready stop at 75
**Complexity:** $O(n)$
Each element will be pushed once, and popped at max once
-- --
Design a special stack
----------------------
> no restrictions on DS to implement
> operations
> - push
> - pop - returns false when stack is empty
> - get_mid - returns false when stack is empty
> - pop_mid - returns false when stack is empty
>
> all operations must take $O(1)$
> stack need not be sorted
- can't use array, because how to pop mid in constant?
- use doubly linked list
- keep a pointer to end of list
- keep pointer to mid
- on push, move the mid to right if needed
- on pop, move the mid to left if needed
- for pop mid, pop the mid and update the mid pointer
-- --
special MIN stack
-----------------
> use stack internally
> operations
> - push
> - pop
> - get_min
>
> All operations in $O(1)$
**Solution 1:**
- store both the value, and the min so far into the stack
- can split into two stacks - for values, and for mins if we wish
**Further Constraint:**
> - only 1 stack
> - stack can have only 1 value and not tuples
- single space for M (min). init with $\infty$
- push:
- if stack empty or E >= M:
- push
- else:
- push T = 2E - M
- M_n = E
- `this keeps track of previous min`
- get_min
- return M
- pop
- T = top
- if T >= M
- pop and return T
- else
- E = M
- M_o = 2M - T
- return E
**Proof:**
- If $E < M$, then $2E - M < E$. Thus, I can know if the min was changed.
- todo: draw diagram by hand
-- --

View File

@@ -0,0 +1,86 @@
TA Onboarding
-------------
- 3 major respinsibilities
- solve doubts during assignments (post lecture) - push the candidates to solve it
- standup session
- help requests
TODOs
-----
- every TA should complete it
- installations, see your students
Classroom
---------
details of current day's class
- During the assignment part, track the performance of each student (live)
- If any student is stuck, ping on flock.
- It's the duty of the TA to make sure that all of their students have solved all by the end of 1 hour
- Share screen / flock the code
- Not a passive interaction
Help Request dashboard
-----------------------
- Students can raise a request towards their TA
- Shows pending requests
- Prioritize and answer based on importance
- Pending on Me vs Mentee
- TA replies
- mentee can communicate back
- pending on mentee = waiting for mentees response
- Open Pool
- if > 12 hour unsolved
- Rewarded based on the number of queries that the TA answered
- Students list - see students who come last in ranking and push them
Standup session
---------------
- Explain the problems we've provided in the lecture. Basically TA session post lecture
- Provide intuitive explanations
- All of Standup Session must be done on the Wacom Tablet
Contest Discussions
-------------------
- Might have to take extra class on weekends
- biweekly contest for students
- explain solutions for those problems
- preapre the explanations beforehand
-- --
- Make sure that they have prepared the material for they day.
- If you feel that there is some issue with the material, notify us so that we can provide an editorial
- 1st session is going to be an intro session - to establish connection and trust
- You should know each of your students personally, and be able to provide detailed feedback about each
- Regarding leaves - notify 24 hours prior and notify the mentees too
-- --
Metric
------
- Daily stand-up ratings.
- No. of help requests resolved.
- Average response time.
- Groups assignment completion percentage.
- Contest performance.
- Cautions:
- Help students, don't blatantly tell them the answer - could lead to your termination. We do perform plagiarism checks
- Students can ask doubt on both flock and interface. Be active on both.
-- --
- If the TA feels that he is good at a topic, and wishes to take classes / remedials on weekends, we would encourage that. Rewards will be performance based.

View File

@@ -0,0 +1,224 @@
Trees and Graphs
----------------
**Graph:**
- nodes
- edges: pairs of nodes that are connected
- directed/undirected
- weighted/unweighted
**Trees:**
- graphs with constraints
- connected
- acyclic
- rooted - contrast with graph
- node has 0 or more children
- node with 0 children is leaf
- node with 1 or more children is non-leaf
- each node has a parent - except for the root
- so, n-1 edges
- since we can make levels, it is a hierarchical DS
**K-ary Tree:**
- node can have at most k children
-- --
Binary Trees
------------
```
o
/ \
o o
\ |\
o o o
```
- Each node has exactly 1 parent (except root)
- Each node has at most 2 children
```python
Node:
value
Node left_child
Node right_child
# typically, we also keep track of parent
Node parent
```
- Full BT - $2^{l+1} - 1$ nodes, if $l$ levels
- Complete BT - full on penultimate level. Nodes in last level fill from the left
- BST
- Balanced Tree
- ...
-- --
Traversals
---------
- DFS:
```
o
/ \
[LST] [RST]
Left and Right subtrees
```
- preorder: whatever operation, do on the node first, then LST, then RST
- inorder: LST, Node, RST
- postorder: LST, RST, Node
- Recursive:
```python
def preorder(node):
if node is null:
return
func(node) # print
preorder(node.left)
preorder(node.right)
```
- Iterative:
- show how the recursion works using a call stack
- so, use a stack - just remember the order to push nodes in
- level-order / bfs
-- --
Zig Zag traversal
-----------------
```
4
6 8
1 3 2 5
========
4 | 8 6 | 1 3 2 5
```
```python
def zigzag(A):
queue = [A]
result = []
level = 0
while queue:
n = len(queue)
vals = [x.val for x in queue]
if level % 2 == 1:
vals = vals[::-1]
result.append(vals)
for i in range(n):
item = queue.pop()
if item.left:
queue.append(item.left)
if item.right:
queue.append(item.right)
level += 1
return result
```
-- --
Vertical traversal
------------------
```
4
6 8
1 3 5
=====
1 | 6 | 4 3 | 8 | 5
If two children, put them in any order
```
store dict of lists of distance from mid
move left = distance - 1
move left = distance + 1
-- --
Tree from Inorder + Preorder
----------------------------
> Given Preporder and Inorder traversals of a Binary Tree, create the tree
- first element of preorder is the Root
- Find root in In-order traversal. Everything on left is in the LST and everything to the right is in the RST
- Recurse
```python
def build(inorder, preorder, in_start, in_end):
if in_start > in_end:
return None
node = Node(preorder[pre_index])
pre_index += 1
if in_start == in_end :
return node
inIndex = search(inorder, in_start, in_end, node.data)
node.left = build(inorder, preorder, in_start, inIndex-1)
node.right = build(inorder, preorder, inIndex + 1, in_end)
return node
def search(arr, start, end, value):
for i in range(start, end + 1):
if arr[i] == value:
return i
inorder = ['D', 'B', 'E', 'A', 'F', 'C']
preorder = ['A', 'B', 'D', 'E', 'C', 'F']
pre_index = 0
root = build(inorder, preorder, 0, len(inorder) - 1)
```
- search can be made $O(1)$ or $O(\log n)$ by storing in hashmap
-- --
Check Valid Traversals
----------------------
> Given Preorder, Inorder and Postorder, check if they represent the same tree
- Use any pair with inorder to create the tree. Then check the remaining order by traversing the tree
-- --
Check Balanced
----------------
> Given Tree, check if balanced
> $$\Bigl | h(\text{left}) - h(\text{right}) \Bigr | \leq c$$
> Holds true for all nodes
```python
def check(node):
if node is null:
return 0
left_height, left_balanced = check(node.left)
right_height, right_balanced = check(node.right)
height = 1 + max(left_height, right_height)
balanced = abs(left_height - right_height) < 1
and left_balanced
and right_balanced
return height, balanced
```

View File

@@ -0,0 +1,200 @@
Tries - Remedial
----------------
```python
class Node:
children: Dict[char, Node]
terminal: bool
character: char
```
Why Tries
---------
Space optimization.
Store the list of all words / movies.
In hashmap, store the keys and values. Key will be (hash, str). Value will be value.
Saves space by using common prefixes
Re**trie**val
```python
def add(node, word):
if not word:
node.terminal = True
return
ch = word[0]
if ch not in node.children:
node.children[ch] = Node(ch)
add(node.children[ch], word[1:])
```
-- --
Search
------
> Given words list, find all words with given prefix
Make trie of the words
-- --
> Given words list, find all words with given suffix.
Make trie of reverse words. Search in reverse.
-- --
Unique Prefix Array
-------------------
> Given list of words, find the unique prefixes.
> input: zebra, dog, dove, duck
> output: z, dog, dov, du
Keep count of how many times a node was used when building the trie.
Each node now stores how many words have that prefix.
counter to child check: zebra, zebras
-- --
Maximum Xor Pair
----------------
> Array with +ve integers
>
Trie with numbers as bitstrings.
Go opposite of current number to find the max xor
-- --
Min Xor Pair
------------
n^2, O(n log n) by sorting
O(n) with tries
-- --
Maximum XOR Subarray
--------------------
Find the prefix XOR.
note: prefix needs inverse function.
xor's inverse it xor.
Now reduced to Max Xor Pair
-- --
Subarray Xor < k
----------------
> count the number of such subarrays
![33f050b7.png](:storage/41b46a45-1bba-436f-ac52-f4c88d4822be/33f050b7.png)
-- --
Number of triplets in array having subarray xor equal
-----------------------------------------------------
> xor(A[i:j]) == xor(A[j:k])
Take prefix xor. If value repeats at i, j, then all splits of A[i:j] work.
just count.
don't keep hashmap, keep trie
-- --
Word Search
-----------
> Given a 2D board and a list of words from the dictionary, find all words in the board.
> Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
![f5890cb4.png](:storage/41b46a45-1bba-436f-ac52-f4c88d4822be/f5890cb4.png)
```python
def findWords(board, words):
trie_root = insert_all(words)
visited = board_of_false
found = set()
for row in board:
for cell in row:
w = backtrack(board, trie_root, i, j, visited, '')
found.add_all(w)
def backtrack(board, node, i, j, visited, s):
if i < 0 or j < 0 or i >= N or j >= N: return
if visited[i][j] return
ch = board[i][j]
if ch not in node.children:
return
node = node.children[ch]
if node.terminal:
result.add(str + ch)
# can remove the terminal flag if needed
visited[i][j] = True
process(board, node, i+1, j, visited, str + ch)
process(board, node, i-1, j, visited, str + ch)
process(board, node, i, j+1, visited, str + ch)
process(board, node, i, j-1, visited, str + ch)
visited[i][j] = False
```
-- --
Make Word
---------
> input: sam, sung, samsung
> output
```
sam:
sam
sung:
sung
samsung:
sam sung
samsung
```
Insert all words into trie
```python
search(w, node):
x, y = w
val = []
if x in trie:
possibles = search(y, root)
val = append x to all possibles
possibles = search(y, node_child)
val.extend(possibles)
return val
```
-- --
> Longest word in dict that can be built one char at a time
> a at
-- --

View File

@@ -0,0 +1,43 @@
# Why do we conduct an Entrance Test ?
The main objective behind conducting the entrance test is to assess the basic knowledge of Data Structures and Algorithms.
To make you ready for [FAANG](https://en.wikipedia.org/wiki/Facebook,_Apple,_Amazon,_Netflix_and_Google), the 6-month immersive online program by Scaler Academy assumes that you already have some prerequisite knowledge of basic programming.
# What to expect in the entrance test
Specifically, we assume that you already know basics including
- How to write a **Loop**
- What an **Array** is
- Simple algorithms like **Searching, Sorting, ..**
- some **basic Maths** like
- How many permutations does the string "Google" have?
- How many bits will be needed to represent the number **1 Million**
You can expect easy to easy/medium level questions on any of the above topics.
We never ask questions related to specific Data Structures like Stacks / Queues, Trees .. since we believe that your success is determined more by how consistentently and passionately you are willing to follow the curriculum, and less by your current knowledge of CSE concepts.
TODO: Link for sample test.
# Which coding language(s) are allowed in the entrance test?
Feel free to code in your preferred language, be it Python, C++, Java, Haskell, Ruby, Javascript or even BrainFuck ;)
Your knowledge of a particular language does not limit your potential as a Software Engineer. Therefore, we never put a constraint on the programming language.
# How to prepare for entrance test
Example problem, solution, approach, general tips for preparation
- Typically how much time is needed to prepare?
- How many hours everyday should one keep for prep?
- Dos and Dont during prep.
- How to use streaks effectively?
- Prepare in a group?
Etc. Imagine if your younger brother/sister is asking this question what all would you suggest?
Your performance in the entrance test will be the major stakeholder regarding your selection. So, make sure to put your best foot forward. To prepare for the test, you can practice easy, easy-medium questions on InterviewBit platform. Have a good grip on your programming skills and make sure you dont face any issues implementing the logic.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 542 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Some files were not shown because too many files have changed in this diff Show More