Add all my notes
243
imperfect_notes/pragy/Arrays + 2d Arrays.md
Normal 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
|
||||||
|
>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
**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**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
First by rows, then by columns (or vice versa)
|
||||||
|
|
||||||
|
Now, add and substract sum to get the desired sums
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**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**
|
||||||
|

|
||||||
|
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
|
169
imperfect_notes/pragy/Binary Search 1.md
Normal 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
|
101
imperfect_notes/pragy/Binary Search 2.md
Normal 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
|
||||||
|
|
163
imperfect_notes/pragy/Binary Trees 2.md
Normal 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
|
||||||
|
|
285
imperfect_notes/pragy/Bit Manipulation.md
Normal 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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
- 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
|
||||||
|
>
|
||||||
|
> 
|
||||||
|
>
|
||||||
|
> 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
|
||||||
|
- 
|
||||||
|
- simply encode each slave number in each column and send
|
||||||
|
- 
|
||||||
|
- whatever comes back are columnwise numbers of active slaves
|
||||||
|
- 
|
||||||
|
|
||||||
|
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
|
166
imperfect_notes/pragy/Graphs 1.md
Normal 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 -
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
1 = land, 0 = water
|
||||||
|
find the number of islands
|
||||||
|
diagonals allowed
|
||||||
|
|
||||||
|
find the number of connected components via DFS
|
||||||
|
|
||||||
|

|
||||||
|
-- --
|
||||||
|
|
||||||
|
grid with 0s and 1s
|
||||||
|
|
||||||
|
capture all 0s surrounded by 1s on all 4 sides
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
shortest distance of all 0s from any 1
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
BFS from all 1s
|
||||||
|
|
||||||
|
inspire from 1 and 2 bombs
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
any shortest distance?
|
||||||
|
|
||||||
|
BFS from all 0s
|
||||||
|
or prev and find min
|
||||||
|
|
180
imperfect_notes/pragy/Greedy Algos.md
Normal 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?
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
> 
|
||||||
|
> 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
|
||||||
|
|
||||||
|

|
||||||
|
-- --
|
||||||
|
|
||||||
|
Flights
|
||||||
|
-------
|
||||||
|
|
||||||
|
> start, end time of flights
|
||||||
|
> num of platforms
|
||||||
|
>
|
||||||
|
|
||||||
|
+1 -1, prefix sum max
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
----------
|
||||||
|
---------------------------
|
||||||
|
|
||||||
|
```
|
80
imperfect_notes/pragy/LLD 1.md
Normal 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**
|
||||||
|
- 
|
||||||
|
- 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
|
||||||
|
|
||||||
|
```
|
295
imperfect_notes/pragy/LLD 2.md
Normal 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
|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
|
219
imperfect_notes/pragy/LLD 3.md
Normal 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**
|
||||||
|
- 
|
||||||
|
- 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
|
||||||
|
- 
|
||||||
|
```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
|
||||||
|
```
|
||||||
|
- 
|
||||||
|
```python
|
||||||
|
class Bounty:
|
||||||
|
prize: int
|
||||||
|
expiry: DateTime
|
||||||
|
|
||||||
|
def claim(): pass
|
||||||
|
|
||||||
|
class Photo:
|
||||||
|
alt_text: str
|
||||||
|
url: str
|
||||||
|
```
|
||||||
|
- Note where we have composition or not
|
||||||
|

|
||||||
|
```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**
|
||||||
|
- 
|
||||||
|
```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
|
||||||
|
- 
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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
|
171
imperfect_notes/pragy/LLD 4.md
Normal 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
|
||||||
|
- ...
|
||||||
|
-- --
|
276
imperfect_notes/pragy/LLD 5.md
Normal 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
|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
221
imperfect_notes/pragy/LLD 6.md
Normal 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
|
||||||
|
|
55
imperfect_notes/pragy/Machine Coding Splitwise.md
Normal 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
|
||||||
|
-------------
|
364
imperfect_notes/pragy/Maths 1 - Deprecated.md
Normal 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
|
||||||
|
- 
|
||||||
|
- 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
|
||||||
|

|
||||||
|
- 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**
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
277
imperfect_notes/pragy/Maths 1 - GCD.md
Normal 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**
|
||||||
|
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|

|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
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
|
||||||
|

|
||||||
|
|
||||||
|
-- --
|
||||||
|
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)
|
225
imperfect_notes/pragy/Maths 2 - Factorization.md
Normal 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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
236
imperfect_notes/pragy/Maths 3 - Modular Arithmetic.md
Normal 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**
|
||||||
|

|
||||||
|
|
||||||
|
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$
|
||||||
|

|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
$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
|
||||||
|

|
||||||
|
|
||||||
|
$C_{n-1}$, because n-1 pairs of moves for $n \times n$ matrix
|
||||||
|
|
143
imperfect_notes/pragy/Project Building - Psych - Coding 1.md
Normal 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)
|
222
imperfect_notes/pragy/Queues.md
Normal 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
|
230
imperfect_notes/pragy/Recursion & Backtracking 1.md
Normal 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
|
308
imperfect_notes/pragy/Recursion & Backtracking 2.md
Normal 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
|
||||||
|
|
||||||
|

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

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

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

|
||||||
|
- Discarding part of the search space
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
Segment Tree
|
||||||
|
------------
|
||||||
|
|
||||||
|
- 
|
||||||
|
- 
|
||||||
|
+ Update: $O(\log n)$
|
||||||
|
+ 
|
||||||
|
+ 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)$
|
||||||
|
-- --
|
||||||
|
|
134
imperfect_notes/pragy/Segment Trees 2.md
Normal 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$
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
> 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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
152
imperfect_notes/pragy/Sorting 1.md
Normal 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
|
||||||
|
--------
|
139
imperfect_notes/pragy/Sorting 2.md
Normal 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?
|
||||||
|
-
|
||||||
|
|
||||||
|
|
||||||
|
-- --
|
300
imperfect_notes/pragy/Stacks.md
Normal 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
|
||||||
|
|
||||||
|
|
||||||
|
-- --
|
86
imperfect_notes/pragy/TA Onboarding.md
Normal 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.
|
||||||
|
- Group’s 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.
|
||||||
|
|
224
imperfect_notes/pragy/Trees & Graphs.md
Normal 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
|
||||||
|
```
|
200
imperfect_notes/pragy/Tries - Remedial.md
Normal 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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
-- --
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
```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
|
||||||
|
|
||||||
|
-- --
|
43
imperfect_notes/pragy/Why Do We Take an Entrance Test.md
Normal 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 Don’t 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 don’t face any issues implementing the logic.
|
||||||
|
|
||||||
|
|
BIN
imperfect_notes/pragy/attachments/02fe9460.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
imperfect_notes/pragy/attachments/03c1d903.png
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
imperfect_notes/pragy/attachments/059e3810.png
Normal file
After Width: | Height: | Size: 168 KiB |
BIN
imperfect_notes/pragy/attachments/09f74762.png
Normal file
After Width: | Height: | Size: 25 KiB |
BIN
imperfect_notes/pragy/attachments/0b1d9eeb.png
Normal file
After Width: | Height: | Size: 764 KiB |
BIN
imperfect_notes/pragy/attachments/151b8e6a.png
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
imperfect_notes/pragy/attachments/186867fa.png
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
imperfect_notes/pragy/attachments/21e3e2c1.png
Normal file
After Width: | Height: | Size: 100 KiB |
BIN
imperfect_notes/pragy/attachments/24debe26.png
Normal file
After Width: | Height: | Size: 89 KiB |
BIN
imperfect_notes/pragy/attachments/255b5284.png
Normal file
After Width: | Height: | Size: 261 KiB |
BIN
imperfect_notes/pragy/attachments/27ac5aa0.png
Normal file
After Width: | Height: | Size: 136 KiB |
BIN
imperfect_notes/pragy/attachments/28b6ef71.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
imperfect_notes/pragy/attachments/2e5f2d2a.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
imperfect_notes/pragy/attachments/301d7713.png
Normal file
After Width: | Height: | Size: 55 KiB |
BIN
imperfect_notes/pragy/attachments/31b63f54.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
imperfect_notes/pragy/attachments/33f050b7.png
Normal file
After Width: | Height: | Size: 111 KiB |
BIN
imperfect_notes/pragy/attachments/3598cec9.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
imperfect_notes/pragy/attachments/3e17ae37.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
imperfect_notes/pragy/attachments/3e86c025.png
Normal file
After Width: | Height: | Size: 313 KiB |
BIN
imperfect_notes/pragy/attachments/3fa0e7ff.png
Normal file
After Width: | Height: | Size: 87 KiB |
BIN
imperfect_notes/pragy/attachments/45bdcdc1.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
imperfect_notes/pragy/attachments/45bde4ea.png
Normal file
After Width: | Height: | Size: 222 KiB |
BIN
imperfect_notes/pragy/attachments/47132572.png
Normal file
After Width: | Height: | Size: 85 KiB |
BIN
imperfect_notes/pragy/attachments/4cded4eb.png
Normal file
After Width: | Height: | Size: 117 KiB |
BIN
imperfect_notes/pragy/attachments/52f49e08.png
Normal file
After Width: | Height: | Size: 186 KiB |
BIN
imperfect_notes/pragy/attachments/5407fbc7.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
imperfect_notes/pragy/attachments/55070460.png
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
imperfect_notes/pragy/attachments/56cbd86d.png
Normal file
After Width: | Height: | Size: 168 KiB |
BIN
imperfect_notes/pragy/attachments/5b3ffff4.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
imperfect_notes/pragy/attachments/5b85a308.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
imperfect_notes/pragy/attachments/5c782630.png
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
imperfect_notes/pragy/attachments/5c8b1184.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
imperfect_notes/pragy/attachments/5d93c037.png
Normal file
After Width: | Height: | Size: 542 KiB |
BIN
imperfect_notes/pragy/attachments/6270c29c.png
Normal file
After Width: | Height: | Size: 139 KiB |
BIN
imperfect_notes/pragy/attachments/65112ffa.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
imperfect_notes/pragy/attachments/69762a56.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
imperfect_notes/pragy/attachments/6b9b2f89.png
Normal file
After Width: | Height: | Size: 37 KiB |
BIN
imperfect_notes/pragy/attachments/6f39934a.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
imperfect_notes/pragy/attachments/741698f7.png
Normal file
After Width: | Height: | Size: 198 KiB |
BIN
imperfect_notes/pragy/attachments/7495d1f7.png
Normal file
After Width: | Height: | Size: 76 KiB |
BIN
imperfect_notes/pragy/attachments/76e2dea7.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
imperfect_notes/pragy/attachments/7b76882f.png
Normal file
After Width: | Height: | Size: 223 KiB |
BIN
imperfect_notes/pragy/attachments/7ddd6b6e.png
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
imperfect_notes/pragy/attachments/812b8234.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
imperfect_notes/pragy/attachments/8598c257.png
Normal file
After Width: | Height: | Size: 121 KiB |
BIN
imperfect_notes/pragy/attachments/8d6e9fbb.png
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
imperfect_notes/pragy/attachments/9158557f.png
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
imperfect_notes/pragy/attachments/93c9f38f.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
imperfect_notes/pragy/attachments/95ddd25e.png
Normal file
After Width: | Height: | Size: 7.9 KiB |
BIN
imperfect_notes/pragy/attachments/96706e2d.png
Normal file
After Width: | Height: | Size: 103 KiB |
BIN
imperfect_notes/pragy/attachments/9e762159.png
Normal file
After Width: | Height: | Size: 144 KiB |
BIN
imperfect_notes/pragy/attachments/aa19c149.png
Normal file
After Width: | Height: | Size: 62 KiB |
BIN
imperfect_notes/pragy/attachments/ad3d4993.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
imperfect_notes/pragy/attachments/b4d22fbe.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
imperfect_notes/pragy/attachments/b824a258.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
imperfect_notes/pragy/attachments/be23bceb.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
imperfect_notes/pragy/attachments/c7aca012.png
Normal file
After Width: | Height: | Size: 107 KiB |
BIN
imperfect_notes/pragy/attachments/ce7714d2.png
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
imperfect_notes/pragy/attachments/dc2d0b12.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
imperfect_notes/pragy/attachments/dd763984.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
imperfect_notes/pragy/attachments/de01b42c.png
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
imperfect_notes/pragy/attachments/e3eb808f.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
imperfect_notes/pragy/attachments/e745eb48.png
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
imperfect_notes/pragy/attachments/e777e692.png
Normal file
After Width: | Height: | Size: 163 KiB |
BIN
imperfect_notes/pragy/attachments/f2f50632.png
Normal file
After Width: | Height: | Size: 546 KiB |
BIN
imperfect_notes/pragy/attachments/f3ecb73e.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
imperfect_notes/pragy/attachments/f51be358.png
Normal file
After Width: | Height: | Size: 474 KiB |
BIN
imperfect_notes/pragy/attachments/f5890cb4.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
imperfect_notes/pragy/attachments/f8a8702a.png
Normal file
After Width: | Height: | Size: 60 KiB |