This repo is about my notes and a record of my practicing of algorithms on Leetcode/lintcode.
Parts of this note refer to Jiuzhang, Labuladong, and other internet recourses. Thanks to them.
(It is wrote mainly in English and barely Chinese. Ignoring the Chinese parts doens't affect the understanding of this repo.)
- 0. Before Starting
- 1. Two Pointers Method (most frequent) - O(n)
- 2. Recursion, Heap and Stack (Hardware), Tree
- 3. Binary Search O(logn)
- 4. Queue/Stack, Set/Map/List
- 5. BFS + Graph
- 6. HashMap + Heap
- 7. DFS
- 8. DC - Divide and Conquer
- 9. Dynamic Programming - Memoization 记忆化搜索 动态规划
- Read through this whole README.md. Get fimilar with "Theory" subsection of each section. No need to dive into those linked files.
- Go through those problems marked with "❗️".
- Go through left problems.
- Clarification. Confirm questions with interviewer, including input, output, examples; discuss about corner cases examples.
- Think out loud. Describe your idea/thoughts before coding. Talk before write.
- Point out your assumption. Like arguments/inputs are in memory, are they sorted already or not.
- Talk through. Write your code while explaining it.
- Introduce your tests and run tests and error handling. Test in real time, use examples given, then edge cases.
- Time and space complexity analysis. Scale analysis.
- Optimal solution or follow up.
- Underlying storage methods: only array (sequential storage) and linked list (chain storage).
- VS
- Operations: traversing and accessing. More specifically, add, delete, search, alter.
- Must-master data structures:
- Arrays, Linked list, Stacks, Queues, Sets, Maps, Binary tress, Heaps, Graphs (Google Code Interview 2:38)
-
Must-master algorithms: (Google Code Interview 3:04)
- Sorting, searching, binary searching
- Divide and conquer
- Dynamic programming and memorizaiton
- Greedy algorithms
- Recursion
- Graph traversal, breadth- depth-first
-
Algorithms with Time complexity O(n):
- 考得频率Test freq.: 2 pointers (without sort) >> 打擂台算法 ~= 单调栈算法 ~= 单调队列算法
-
Common Time Complexity:
Time Complexity | Possible corresponding Syntax | Note |
---|---|---|
O(1) | Bit Operation 位运算 | Usually won't be asked. 常数级复杂度,一般面试中不会有 |
O(logn) | Binary Search 二分法, Doubling 倍增法, Fast exponentiation algorithm 快速幂算法, Euclidean algorithm 辗转相除法 | Mainly BS. 比O(n)更好几乎一定是BS。 |
O(sqrt(n)) | Factorization/Decomposition prime factors 分解质因数 | Barely 极少 |
O(n) | Enumeration 枚举法, Two Pointers (w/o sorting) 双指针算法, Monotonic Stack Algorithm 单调栈算法, KMP KMP算法,Rabin Karp,Manacher's Algorithm | A.k.a linear time complexity. 又称作线性时间复杂度 |
O(nlogn) | Quick Sort 快速排序, Merge Sort 归并排序, Heap Sort 堆排序. Or work on O(logn) data structure. | O(logn) Data Structure includes Balanced Tree, Heap, RB-tree. |
O(n^2) | Enumeration 枚举法, Dynamic Programming 动态规划, Dijkstra | |
O(n^3) | Enumeration 枚举法, Dynamic Programming 动态规划, Floyd | |
O(2^n) | Combination related search questions. 与组合有关的搜索问题 | |
O(n!) | Permutation related search questions. 与排列有关的搜索问题 | |
- Find all plans/solutions problems
- paths == plans == nodes combinations/permutations
- DFS (with recursion)
- BFS
- Find amount of all plans
- DP
- Find best among all solutions problems
- Iteration/loop
- Greedy/ Eplison Greedy
- Dynamic Programming
- MDP/ Reinforcement Learning
- Shortest Path problems
- BFS (simple Graph)
- Floyd, Dijkstra, Bellman-ford, SPFA (complex graph)
- Longest Path problems
- Graph can be layered: DP
- Cannot: DFS
- Face to Face Two Pointers 相向双指针 (most frequently asked)
- Two Sum type
- sum of two numbers.
- sum of three numbers.
- Reverse type
- 判断回文串 palindrome.
- 翻转字符串 flip string.
- Partition type
- quick sort.
- color sort.
- Two Sum type
- Back to Back Two Pointers 背向双指针 (only below 3 tyeps:)
- Longest Palindromic Substring 最长回文子串 - 中心线枚举算法
- Find K closet elements (also in binary search)
- Square of sorted array
- Same Direction Two Pointers 同向双指针
- Sliding Window 滑动窗口类
- Fast & Slow pointers 快慢指针类
Time Complexity | Space Complexity | |
---|---|---|
Use hashmap | O(n) | O(n) |
Use [sort O(nlogn)+] 2 pointers O(n) | O(nlogn) | O(1) |
- Face to Face Two Pointers 相向双指针 (most frequently asked)
- Two Sum type
- sum of two numbers.
- ❗️Easy 1. Two Sum (2 pointer base - O(nlogn), hashmap O(n)); 2pointers template
- ❗️Easy 170. Two Sum III - Data structure design
- ❗️Two sum note, 2 pointers VS hashmap
- Easy 167. Two Sum II - Input array is sorted;
- Easy 1099. Two Sum - Less than or equal to target
- Medium 611. Valid Triangle Number
- Note ask for plan combinations and plans count 求具体方案和方案个数
- sum of three numbers.
- Medium 15. 3 Sum
- Medium 18. 4 sum, same array, ask for plan combinations
- Medium 454. 4sum_II.md, 1 arrays, ask for plans count. Barely meet. 折半搜索. O(n^k) -> O(n^(k/2))
- Hard i89. K sum DFS DP 抽空练习
- sum of two numbers.
- Reverse type
- palindrome 判断回文串.
- flip string 翻转字符串.
- Partition type (Must partition if ask for no extra mem)
- quick sort.
- ❗️Quick sort merge sort quick select note Partition template
- ❗️Medium 912. Sort an Array (quick & merge sort)
- merge sort. Easy 88. Merge Sorted Array
- Hard 493. Reverse Pairs MS 抽空练习
- Medium i144. Interleaving Positive and Negative Numbers
- Easy i373. Partition Array by Odd and Even
- Medium i49. Sort Letters by Case
- quick select
- ❗️Medium 215. Kth Largest Element in an Array sort/partition/priority queue/heap
- Easy 703. Kth Largest Element in a Stream 抽空练习
- Medium 1985. Find the Kth Largest Integer in the Array 抽空练习
- color sort
- ❗️Medium 75. sort colors O(n)
- Medium i143. rainbow sort, k-colors sort O(nlogk) 抽空练习
- Easy
- Hard 295. Find Median from Data Stream 抽空练习
- quick sort.
- Two Sum type
- Back to Back Two Pointers 背向双指针 (only below 3 tyeps:)
- Longest Palindromic Substring 最长回文子串 - 中心线枚举算法
- Find K closet elements (also in binary search)
- Square of sorted array
- Same Direction Two Pointers 同向双指针
- Sliding Window 滑动窗口类
- Fast & Slow pointers 快慢指针类
- Easy 283. Move zeroes
- Definition, Stopping Condition, Divide. 递归的定义,出口,拆解。
- 递归的定义:接受什么参数,返回什么值,代表什么意思
- 递归的拆解:每次递归都是为了让问题规模变⼩
- 递归的出⼝:必须有⼀个明确的结束条件
=> 得到⼀个可供其他函数调⽤的递归函数
Heap: | Stack: | |
---|---|---|
Store what? | store the object got by "new" | store the reference to object, variables, arrays, function calls |
Size | No limit. All left mem space. | Limited. Usually as small as few MB. (Stack Overflow, Segment Fault if recursion depth is big) |
- Java: About 18615 recursion delpth.
- C/C++: About 262009 recursion delpth.
- Python: About 998 recursion delpth. Not stackoverflow. But “RuntimeError: maximum recursion depth exceeded” which is a setting.
Pass by value | Pass by reference | |
---|---|---|
Java | Java Primitive Data Types (byte, short, int, long, float, double, char, boolean) | Java Class Instances |
Those class elements with 'final'. | ||
Python | Python Value types. Similar to Java | Python Reference types. Similar to Java |
C++ | Default | Parameters with '&' |
Diff: copy content? | Yes. (more space/time, don't affect upper level) | No. (affect upper level) |
- Binary Tree
- Inorder Traversal
- Preorder Traversal
- Postorder Traversal
- Construct binary tree from 2 traversals
- from Inorder and (Preorder or Postorder Traversal)
Use Recursion | Don't Use Recursion |
---|---|
If interviewer ask so. | If interviewer ask not. |
Recursion depth is not big. No Stackoverflow would happen | Recutsion depth is deep. May stackoverflow. |
Don't use recursion on LinkedList (Easy to have 100k nodes). | |
Cannot implement using non-recursion. | Easy to implement using non-recursion (like binary rearch). |
Common: DFS uses recursion. | Common: Binary tree inorder traversal uses non-recursion. |
Other algorithms often use non-recursion. | |
Note recursion (more details inside if needed)
- ❗️Easy 509. Fibonacci, O(2^n) -> O(n) Recursion, Memorized Search, Rolling Array
-
Easy 190. Reverse Bits 抽空练习
-
Easy 704. Classical Binary Search Recursion, BS
-
Medium 251. Flatten 2D Vector
- ❗️Easy 206. Reverse Linked List
- ❗️Easy 94. Binary Tree Inorder Traversal Recursion/Stack
- ❗️Medium 106. Construct Binary Tree from Inorder and Postorder Traversal
- ❗️Medium 113. Path Sum II DFS, Backtrack
- Easy 112. Path Sum
- Recursion
- Binary Search
- Divide and Conqer
- Dynamic Programming
- For BS, the array must be sorted (ascending or descending).
- BS also works for some question may not be sorted, like i585.Maximum_Number_in_Mountain_Sequence
- BS on answer-set instead of question-input.
Time Complexity | Space Complexity | Muse be sorted? | |
---|---|---|---|
Binary Search | O(logn) | Same | Ask the array to be sorted. |
For-loop Search | O(N) | Same | No |
- Recursion
- For-loop (best choice)
- Both
- Attention Point 1: start + 1 < end
- Attention Point 2: start + (end - start) / 2. Overflow if mid = (start + end ) / 2 in Java/C++.
- Attention Point 3: Seperate cases for =, <, >. Don't change mid value.
- Attention Point 4: Deal with start and end after while-loop.
- Overall idea: Down the range from n to 2 (start or end); Deal with Start and End. (If use while start < end or start <= end, you may encounter dead-loop.)
start, end = 0, len(nums) - 1
while start + 1 < end: # point 1
mid = start + (end - start) / 2 # point 2
if nums[mid] < target: # point 3
start = mid
elif nums[mid] == target:
end = mid # (if ask for first pos) or return mid (if ask for exist)
else:
end = mid
if nums[start] == target: # point 4. These 2 if may exchange
return start
if nums[end] == target:
return end
return -1
Note Binary Search (more details inside if needed), Template
-
❗️Easy 704. Classical Binary Search BS, Recursion
-
Split array to OO|XX two parts.
- ❗️Medium 852. Peak Index in a Mountain Array Increase firstly and then decrease.
- Medium 658. Find K Closest Elements
- ❗️Medium 153. Find Minimum in Rotated Sorted Array (Unique elements) O(logn)
- ❗️Hard 154. Find Minimum in Rotated Sorted Array II (duplicate elements) O(logn)~ Worst O(n)
- ❗️Medium 33. Search in Rotated Sorted Array (Unique elements) 2times BS, 1time BS
-
BS on unorderred array
- ❗️Medium 162. Find Peak Element
- Medium 1901. Find a Peak Element II 还没做
- ❗️Medium 162. Find Peak Element
-
BS on answer set
- ❗️Hard i183. Wood Cut O(n log MAX(L))
- Easy 69. Sqrt(x)
- Hard 302. Smallest Rectangle Enclosing Black Pixels 还没做
- ❗️Hard i183. Wood Cut O(n log MAX(L))
-
❗️Medium i447. Search in a Big Sorted Array Exponential Backoff 倍增法
- Other uses EB:
- Dynamic Array (ArrayList in Java, Vector in C++)
- Network Retry
- Other uses EB:
- Queue: FIFO, abstract data type. Widely used for BFS.
- Array: Better performance for random access: O(1).
- LinkedList: Better performance for insert and delete: O(1).
- Use Array
- Use Array to implement Circular Queue
- Use LinkedList
- Use ArrayList
- Java Interface Queue (Class PriorityQueue, AbstractQueue)
- Java Interface Deque (Class ArrayDeque)
- Set
- Map
- List
- Queue
Set | Duplicate | Null | Order |
---|---|---|---|
HashSet | No duplicate elements | Can have null | Non Order |
TreeSet | No duplicate elements | Cannot have null | In Order (Default alphabet order) |
Map | Duplicate | Null | Order |
---|---|---|---|
HashMap | key cannot duplicate,value can | key and value both can be null | Non order |
TreeMap | key cannot duplicate,value can | no null | In Order (by key) |
List | Better at |
---|---|
LinkedList | Random access: get, set. O(1) |
ArrayList | Add, Delete (Given position). O(1) |
Queue | Under Infrastructure | FIFO |
---|---|---|
PriorityQueue | Implement base on Heap | Non-FIFO (order by natural order (alphabet order) if no comparator designed, or order by priority if designed) |
Queue | Implement base on LinkedList | FIFO |
Interface | Abstract Class | |
---|---|---|
Keyword | "implements" | "extends" |
Methods | Abstract and non-abstract methods. (Java 8 has default and static methods). | Only abstract methods. Abstract methods in Abstract class must be implemented by sub-calss. |
Class Variables | Final (default), static | Final, non-final, static, non-static |
Class Members | Public (default) | Public, Private, Protected |
Multiple Inheritance | Yes | No (C++: Yes) |
Implementation of each other | Cannot impl Abstract Class | Can impl Interface |
Extend | Can extend other interfaces | Can extend other one class and implement multiple interfaces |
Java/C++ | Partially Interexchangable in Java | C++ only has abstract class |
Note Interface, Abstract Class (more details inside if needed)
-
❗️Easy 232. Implement Queue
- Java:
- Using Array
- Array (Circular Queue)
- Class LinkedList
- Interface Queue (Class LinkedList)
- Abstract Class (AbstractQueue)
- Interface Deque (Class ArrayDeque)
- Class ArrayList
- Implement Queue Using Stack (Use 2 stacks)
- Python:
- list (data type)
- collections (module, containers datatypes) - Class deque
- queue class (synchronized) - Queue (no peek() method)
- Java:
-
❗️Easy 225. Implement Stack
- Java:
- Class Stack
- Class LinkedList
- Class ArrayList
- Interface Deque (Class ArrayDeque)
- Implement Stack Using Queue (Sol1: use 2 queues; Sol2: use 1 queue)
- Python:
- list (data type)
- collections (module, containers datatypes) - Class deque
- queue class (synchronized) - LifoQueue (no peek() method)
- Implement Stack Using Queue (use queue.Queue())
- Java:
-
If just use Queue/Stack:
Java:
It's better to use ArrayDeque instead of LinkedList when implementing Stack and Queue in Java. ArrayDeque is likely to be faster than Stack interface (while Stack is thread-safe) when used as a stack, and faster than LinkedList when used as a queue. Refer Link.
Deque/Queue<E> myqueue = new ArrayDeque<E>();
(interface Deque extends interface Queue )
Deque<E> mystack = new ArrayDeque<E>();
(use like a stack) (ArrayDeque is faster than LinkedList)
Queue Method (Use this column methods directly) | Equivalent Deque Method | Stack Method (Use this column methods directly) | Equivalent Deque Method |
---|---|---|---|
add(e) | addLast(e) | push(e) | addFirst(e) |
offer(e) | offerLast(e) | ||
remove() | removeFirst() | ||
poll() | pollFirst() | pop() | removeFirst() |
element() | getFirst() | ||
peek() | peekFirst() | peek() | peekFirst() |
Python:
from collections import deque
mystack = deque()
# left as top
myqueue = deque()
(left as head/first)(synchronize Queue is slower)
Queue Method (Use this column methods directly) | Equivalent collections.deque Method | Stack Method (Use this column methods directly) | Equivalent collections.deque Method |
---|---|---|---|
push | myqueue.append(x) | push | mystack.appendleft(x) |
pop | myqueue.popleft() | pop | mystack.popleft() |
peek | if myqueue:return myqueue[0] else: return -1 | top | if mystack: return mystack[0] |
empty | len(myqueue) == 0 | empty | len(mystack) == 0 |
- Adjacency Matrix
int[][] matrix
; 2D array.- Space: O(n^2)
[
[1,0,0,1],
[0,1,1,0],
[0,1,1,0],
[1,0,0,1]
]
- Adjacency List (More frequently used)
- Each node records its neighbors.
- Space O(E). Worst case O(n^2).
- Implement an Adjacency List:
- Use self-defined Class
- more popular in Software Engineered, recommend if enough time
- Use HashMap<T, HashSet>
Map<Integer, Set<Integer>> myGraph = new HashMap<>(); myGraph.put(0, new HashSet<Integer>();
- (less code)
- Use self-defined Class
[
[1],
[0,2,3],
[1],
[1]
]
Java:
class DirectedGraphNode {
int label;
List neighbors;
...
}
Python:
def DirectedGraphNode:
def init(self, label):
self.label = label
self.neighbors = [] # a list of DirectedGraphNode's
...
Java:
Map<Integer, Set<Integer>> myGraph = new HashMap<Integer, HashSet>();
myGraph.put(0, new HashSet<Integer>();
Python:
adjacency_list = {x:set() for x in nodes}
adjacency_list = {}
for x in nodes:
adjacency_list[x] = set()
- level order traversal 分层遍历
- traversal hierarchical a Grapg, Tree, Matrix
- BFS on tree
- BFS on Graph: O(V+E)
- BFS on Matrix: O(row * col)
- shortest path for simple Graph (all edge length are 1)
- traversal hierarchical a Grapg, Tree, Matrix
- connected component 连通块问题
- find all connected cell
- non-recursion implementation for find-all-plans problem
- topological sort 拓扑排序
(几乎每个公司面试都会有一道拓扑排序题)
- Can also be done using DFS. BFS much easier. (When both can, always use BFS).
- TS must for DAG (Directed Acyclic Graph). If not DAG then no TS. If DG has not TS then it must be cyclic.
- Examples: Course Select, Compile Order
- Questions:
- find any Topological order
- whether there is TO (a graph may have #TO >= 0)
- If len(the answer of previous one) == #nodes then exist. Or don't exist.
- find whether only one TO
- Yes if queue.size == 1 during whole process. (bc only one choose for next node)
- If at some step queue.size > 1 then not only one. (more than 1 choose)
- find the TO with min lexicographical order
- Min/Max -> use PriorityQueue
- Java:
Queue<> myqueue = new PriorityQueue<>()
myqueue.poll()
myqueue.offer(newnode)
- Python:
myqueue = []
heapify(myqueue)
heappop(myqueue)
heappush(myqueue, newnode)
- Queue is used to record which nodes need to be process
- Hashtable to record visited nodes if necessary:
- to avoid repeated calculation
- to prune in tree
- to avlid cycle in graph
- Java: HashSet/HashMap
- Python: set/dict
- C++: unordered_set/unordered_map
- Single Queue (simplest, recommend)
- Two Queues (easier understand)
- Dummy Node 哨兵节点
- Usually point to first node in LinkedList
- pop(): delete head node.
DummyNode.next = DummyNode.next.next
- In BFS: used to indicate end of each level.
- Advantage: reduce one for-loop.
- ❗️BFS Template Queue record nodes to process. HashTable record visited node to prune or avoid cycle.
- Use BFS (always easier).
- DFS recursion easily stackoverflow.
- DFS iteration is hard and interviewer may also don't understand.
- You barely write BFS wrongly
- BFS for shorted path
- Simple graph: BFS
- Complex graph: Floyd, Dijkstra, Bellman-ford, SPFA. (Usually not appear in interviews)
- Longest path:
- The graph can be layered (directed, no cycle): DP
- Cannot: DFS
- BFS for Binary Tree vs BFS for Graph
- Tree is a special Graph
- Tree has no circle so no need to record visited nodes
- HashSet/dict/unordered_map -> record visited nodes
- Possible circle in graph, where one node will be enqueued more than 1 times -> olution: record visited nodes
- One plan == one path
- All plans == find all paths (like connected-component problems)
- Medium 78. Subsets DFS/BFS
- 序列化 Hard 297. Serialize and Deserialize Binary Tree
- 如果同时给了start and end point
- 图的话一般是无向图
- Bi-BFS Template
-
level order traversal 分层遍历
- ❗️Medium 102. Binary Tree Level Order Traversal 3 types BFS (1 queue, 2 queues, dummy node), DFS
- ❗️探索Medium 1197. Minimum Knight Moves BFS + Pruning, bi-BFS, DP等多解法
- ❗️总结BFS Template Queue record nodes to process. HashTable record visited node to prune or avoid cycle.
- Simple graph shortest path 简单图最短路径
- Hard 127. Word Ladder BFS分层/不分层, bi-BFS
- ❗️Medium 102. Binary Tree Level Order Traversal 3 types BFS (1 queue, 2 queues, dummy node), DFS
-
Connected component 连通块问题
- ❗️Medium 133. Clone Graph
- BFS on Matrix (Change coordinates)
- ❗️Medium 200. Number of Islands BFS / Union Find
- Medium 1197. Minimum Knight Moves 上面做过
- BFS on Graph
-
Topological Sorting 拓扑排序 (BFS on Graph)
- find any Topological order
- ❗️Medium i127 Topological Sorting
- Medium 207. Course Schedule
- whether there is TO (a graph may have #TO >= 0)
- ❗️Medium 210. Course Schedule II
- find whether only one TO
- ❗️Medium 444. Sequence Reconstruction
- find the TO with min lexicographical order
- ❗️Hard 269. Alien Dictionary
- find any Topological order
-
Bi-BFS
- Medium 1197. Minimum Knight Moves bi-BFS
- Hard 127. Word Ladder BFS分层/不分层, bi-BFS
- O(1)
- get(key), set(key, value)
- actually O(size of keys)
- Capacity, load factor, rehash
- Java HashMap: default initial capacity (16) and the default load factor (0.75).
- HashSet: the backing HashMap instance has default initial capacity (16) and load factor (0.75).
- rehash when size >= 16 * 0.75 = 12
HashMap | HashSet | HashTable |
---|---|---|
Implement Map interface | Implement Set intergace | Implement Map interface. Inherits Dictionary class. |
Store key-value pair | Store object | Store key-value pair |
Unique key | Unique element | Unique key |
One null as key. Multiple null can be values. | One null element allowed | No null as key neither value |
put() - add element | add() - add element | put() - add element |
HashMap uses key to calculate Hashcode | HashSet uses the member object to calculate the hashcode value. The hashcode may be the same for two objects, so use the equals() method to determine the equality of the objects. If the two objects are different, return false | HashTable uses key to calculate Hashcode |
It is not Thread-Safe because it is not Synchronized but it gives better performance. | Like HashMap, it is not Thread-Safe because it is not Synchronized. | It is Thread-Safe because it is Synchronized. |
HashSet | TreeSet | LinkedHashSet |
---|---|---|
HashSet is fastest than LinkedHashSet and TreeSet | TreeSet is slow when compared with both Hashset and LinkedHashSet | LinkedHashSet is second fastest next to HashSet |
HashSet does not maintain any order | TreeSet maintains Sorting Order | LinkedHashSet maintains insertion order |
HashSet allows null | TreeSet does not allow null | LinkedHashSet allows null |
HashSet uses equals() method | TreeSet uses compareTo() method | LinkedHashSet uses equals() method |
HashSet backed by HashMap | TreeSet backed by NavigableMap | LinkedHashSet backed by HashSet |
- Python - set()/dict()
- Collision: open-hashing.
- C++ - unordered_set() / unordered_map()
- open hashing / closed addressing / seperate chaining
- keys are stored in linked lists attached to cells of a hash table.
- closed hashing / open addressing/ linear probing
- all keys are stored in the hash table itself without the use of linked lists.
- tomb (deleted element flag)
- double hashing (reduce hitting clumps possibility)
- Easy 706. Design HashMap
- Easy 705. Design HashSet
- Except Binary Tree, 90% of DFS is combination or permutation problems. Especially combination.
- DFS with Combinations
- C(n, k) = n! / {k! (n-k)!}
- Implicit graph search problem
- If one problem doesn't tell you what are vertexes and edges but ask you to search, then it's implicit graph searching problem.
- Firstly we need to figure out what are vertexes and edges.
- ❗️Medium 78. Subset
- Find all plans problem -> Use DFS
- Solution 1 Combination Special DFS 分层
- Solution 2 General DFS 不分层
- Solution 3 BFS
- ❗️Medium 90. Subset ii Duplicate elements
- Remove duplicate while searching
- Sort and compare to avoid duplicate
- Hash (Python: set/dict; Java: HashSet/HashMap)
- Remove duplicate while searching
- DFS with Permutations
- Permutation considers order. P(n, k) = A(n, k) = n factorial = n!
- ❗️Medium 46. Permutations Distinct elements. 1.DFS-Permutation-Recursion; 2.Non-Recursion
- Combination DFS vs Permutation DFS
- Search Tree shape
- Templates
- DFS Time Complexition
- O(#all-plans * time-to-build-one-plan)
- Combinations: O(2^N * N)
- Permutations: O(N! * N)
- => small depth and may large width => DFS
- O(#all-plans * time-to-build-one-plan)
- Find all plans meet requirements 找所有满足某个条件的方案
- Find all paths 找到图中的所有满足条件的路径
- 路径 == 方案 == 图中节点的排列组合
- Can be solved using BFS?
- Yes
- Need to convert find-all-paths to find-all-nodes
- The space complexity of BFS depends on its width 宽度优先搜索的空间复杂度取决于宽度
- The space complexity of DFS depends on its depth 深度优先搜索的空间复杂度取决于深度
- If the search tree is deep but not wide then BFS
- Matrix uses BFS
- For example, in matrix, the width is <= sqrt(n) while depth is <= n^2 so it's better to use BFS.
- Matrix uses BFS
- If the search tree is wide but not deep then DFS
- Combinations/Permutations use DFS
- They are O(2^n)/O(n!) so the n cannot be large => the depth won't be large but the width might be large => DFS
- Combinations/Permutations use DFS
-
Combinations
- Medium 39. Combination Sum distinct, use multiple times
- Medium 40. Combination Sum II duplicate, use once
- Medium 216. Combination Sum III k members sum up to target (Medium ==i90. K Sum II), use once
- Medium 377. Combination Sum IV total amount of combinations (== Hard i89. K Sum) - DP 以后再做
- Medium 77. Combinations Recursion, Stack以后再做
- Medium 17. Letter Combinations of a Phone Number
- Medium 39. Combination Sum distinct, use multiple times
-
DFS on Matrix
-
Medium 79. Word Search one target word
- Hard 212. Word Search II multiple target words. Prefix map/Trie
- Hard i638. Boggle Game same as 212
- Hard i1848. Word Search III multiple target words in continous sequence. Trie.
- Hard 212. Word Search II multiple target words. Prefix map/Trie
-
Hard 127. Word Ladder 求最优方案之一 BFS分层/不分层, bi-BFS. (Review first先复习下这个方便和下一个对比)
- Hard 126. Word Ladder II 求全部最优方案path BFS+DFS
-
-
Permutations
- Medium 46. Permutations Distinct elements. 1.DFS-Permutation-Recursion; 2.Non-Recursion/Stack.
- Medium 47. Permutations II duplicate elements.
- Medium 31. Next Permutation
-
Implicit Graph/Tree
- Hard 51. N-Queens Each possible move is a tree node. Ask all-plans.
- Hard 52. N-Queens 2 Ask #all-plans. Almost same.
- Hard 37. Sudoku Solver DFS
- Medium 36. Valid Sudoku Array Traverse
- Hard 980. Unique Paths III DFS, DP
- Hard 51. N-Queens Each possible move is a tree node. Ask all-plans.
TSP DFS, pruning, DP
- Shortest Path Visiting All Nodes
- Minimum Time Visiting All Points
然后完成bfs bi-bfs 然后7dc 然后dp
Recursion | DFS | BackTracking |
---|---|---|
Recursion function: One way to implement the program, i.e. a function calls itself. | DFS can be implemented by using Recursion fucntion. | Backtracking method: It is DFS algorithm. |
Recursion algorithm: The result of bigger problems depend on the result of smaller problems. So use the recursion function to solve the smaller problems. | DFS can be implemented without using Recursion fucntion, for example you design a stack and operate by hand yourself. | Backtracking operation: when the recursion function return to its previous layer, some parameters need to be changed back to their previous values. |
Usually when we say recursion, we mean the recursion function. | DFS is a traversal/searching algorithm. | |
Traversal 遍历法 | DC 分治法 |
---|---|
A helper guy stores all visited nodes | Ask your gangs to solve the sub-problem and you sum up their results yourself |
Usually use a global variable or shared argument | Usually use return-value to store results of sub-problems |
- Easy 257. Binary Tree Paths (find all paths) DFS, 遍历法 vs 分治法
- Binary tree DC template
- Easy 110. Balanced Binary Tree Traversal and DC
-
❗️Easy 120 Triangle
- DFS-Traverse O(2^n),
- Divide & Conquer O(2^n),
- DC-with-Hashmap/Memoization Search O(n^2)
- 以后还待加上DP
-
Memoization Search 记忆化搜索
- Use Hashmap/Dict to record intermidiate results of searching process, to avoid repeated calculation
- Record the result of calculation, so next time meet same arguments, directly return record withoug calculating again
- Reduce exponential time complexity to polynomial lelve (O(2^n) to O(n^2))
-
Memoization Search Usage Limit 对这个函数的限制
- The function must have argument and return value. If not then cannot hashmap it.
- The function need to be pure function, which means the return value is only affected by the arguments
- Like cache in Architecture/System Design
-
Memoization Search Essence: is DP 记忆化搜索的本质就是动态规划
- MS is an implementation method of DP
- DP implementation methods:
- Memoization Search
- Non-recursion/Multi-level for loop
- see more in below subsection
-
MS vs DC
- Key difference is: whether has repeated computing
- After Divide step:
- If left and right sub-parts have overlap => is DP
- If not => is DC
-
MS advantages and disadvantages:
- cons
- If Time complexity is O(n) and Recursion Depth is O(n) then it will stackoverflow
- Recursion Depth should < 100,000
- Easy i1300 Bash Game
- If Time complexity is O(n^2) and Recursion Depth is O(n) then it will not stackoverflow
- MS is not suitable for O(n) problems becuase of the risk of stackoverflow
- If Time complexity is O(n) and Recursion Depth is O(n) then it will stackoverflow
- pros
- Add few lines from DC
- State Transition is simple
- cons
- DP is a thought, not an algorithm
- Key: Divide big problems into smaller problem 核心思想:由大化小
- Algorithms using same thought:
- Recursion
- Divide and Conquer (DC)
- DP vs DC
- whether there is overlap subproblems
- For example:
- Binary tree, left sub-tree and right sub-tree: on overlap => DC
- Triangle problem: left child and right child: have overlap => DP
- also see "MS vs DC" above
- For example:
- whether there is overlap subproblems
- DP vs Greedy
- DP would loss of current benefits for long-term benefits
- Greedy always pursue the maximization of current benefits
- DP implementation
- Memoization
- For-loop
- Top-down
- Bottom-up
- DP 4 elements:
- State 动规的状态
- Function (state transition function) 动规的方程
- Initialize (base case) 动规的初始化
- Answer 动规的答案
- DP 4 elements 1-to-1 correspond with Recursion 3 elements 一一对应
- min value/max value 最值问题
- number of all plans 方案总数
- feasibility 可行性
DP | 一一对应 | Recursion |
---|---|---|
DP State 动规的状态 | dp[i] or dp[i][j] for sub-problems. 用 dp[i] 或者 dp[i][j] 代表在某些特定条件下某个规模更小的问题的答案。 规模更小用参数 i,j 之类的来划定 |
Recursion Definition 递归的定义 |
DP Function 动规的方程 | How problems are divided into sub-problems. 大问题如何拆解为小问题.Use smaller scale state to derive dp[i][j] . dp[i][j] = 通过规模更小的一些状态求 max / min / sum / or 来进行推导 |
Recursion Divide 递归的拆解 |
DP Initialize 动规的初始化 | Base case. 设定无法再拆解的极限小的状态下的值. E.g. dp[i][0] or dp[0][i] |
Recursion Stop Condition 递归的出口 |
DP Answer 动规的答案 | What is asked for? 最后要求的答案是什么. E.g. dp[n][m] or max(dp[n][0], dp[n][1] … dp[n][m]) |
Recursion Calling 递归的调用 |
- This is why Memoization (using recursion) can be one implementation of DP.
Note DP (more details inside if needed)
- Memoization
- Easy i1300 Bash Game
- DP