算法通关40讲
算法/数据结构/系统设计
时间复杂度/空间复杂度
Big O notation O(1): Constant Complexity(常数复杂度) O(log n): Logarithmic Complexity(对数复杂度) O(n): Linear Complexity(线性时间复杂度) O(n^2): N square Complexity(平方) O(n^3): N square Complexity(立方) O(2^n): Exponential Growth(指数) O(n!): Factorial(阶乘)
Array & Linked List
Array
复杂度分析 Access: O(1) Insert: 平均O(n),如果插入到最后一个则是O(1) Delete: 平均O(n),如果删除最后一个则是O(1)
Linked List
Doubly Linked List
复杂度分析 space: O(n) prepend: O(1) append: O(1) lookup: O(n) insert: O(1) delete: O(1)
Stack & queue
Stack - First In First Out (FIFO) Queue - First In Last Out (FILO)
PriorityQueue
Stack - First In First Out (FIFO) Queue - First In Last Out (FILO) PoriorityQueue - 优先队列
实现机制
- Heap (Binary, Binomial, Fibonacci)
- Binary Search Tree
两种堆
- 小顶堆
- 大顶堆
HashTable & Set
1. Hash Function 2. Hash Collisions
Tree & Binary Tree & Binary Search Tree
Linked List 就是特殊化的 Tree Tree 就是特殊化的 Graph
TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || root == p || root == q) return root;
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
return left == null ? right : right == null ? left : root;
}
def lowestCommonAncestor(self, root, p, q):
if p.val < root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
if p.val > root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
return root
def lowestCommonAncestor(self, root, p, q):
while root:
if p.val < root.val > q.val:
root = root.left
elif p.val > root.val < q.val:
root = root.right
else:
return root
二叉树遍历
前序(Pre-order)根-左-右 中序(In-order)左-根-右 后序(Post-order)左-右-根
def preorder(self, root):
if root:
self.traverse_path.append(root.val)
self.preorder(root.left)
self.preorder(root.right)
def inorder(self, root):
if root:
self.inorder(root.left)
self.traverse_path.append(root.val)
self.inorder(root.right)
def postorder(self, root):
if root:
self.postorder(root.left)
self.postorder(root.right)
self.traverse_path.append(root.val)
递归 & 分治
Recursion
def recursion(level, param1, param2, ...):
# recursion terminator
if level > MAX_LEVEL:
print_result
return
# process logic in current level
pocess_data(level, data...)
# drill down
self.recursion(level + 1, p1, ...)
# reverse the current level status if needed
reverse_state(level)
Divide & Conquer
def divide_conquer(problem, param1, param2, ...):
# recursion terminator
if problem is None:
print_result
return
# prepare data
data = prepare_data(problem)
subproblems = split_problem(problem, data)
#conquer subproblems
subresult1 = self.divide_conquer(subproblems[0], p1, ...)
subresult2 = self.divide_conquer(subproblems[1], p1, ...)
subresult3 = self.divide_conquer(subproblems[2], p1, ...)
...
# process and generate the final result
result = process_result(subresult1, subresult2, subresult3, ...)
贪心算法(Greedy Algorithms)
广度优先搜索(Breeadth-First-Search)
How a BFS Would Traverse This Tree
def BFS(graph, start, end)
queue = []
queue.append([start])
visited.add(start)
while queue:
node = queue.pop()
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
queue.push(nodes)
# other processing work
深度优先搜索(Depth-First-Search)
How a DFS Would Traverse This Tree
BFS vs DFS
DFS 递归写法
visited = set()
def dfs(node, visited):
visited.add(node)
# process current node here.
...
for next_node in node.children():
if not next_node in visited:
dfs(next_node, visited)
DFS 非递归写法
def DFS(self, tree):
if tree.root is None:
return []
visited, stack = [], [tree.root]
while stack:
node = stack.pop()
visited.add(node)
process(node)
nodes = generate_related_nodes(node)
stack.push(nodes)
# other processing work
...
二分查找(Binary Search)
Union & Find
LRU Cache
三个要点:
- Least Recently Used
- Hash Table + Double LinkedList
- O(1) get and O(1) set
常用两种:
- LFU - least frequently used
- LRU - least recently used
Bloom Filter
两个特点:
- 空间效率和查询速度远超一般算法
- 查询不存在肯定不存在
- 查询存在但不一定存在,需要再次确认
- 查询不存在肯定不存在情况
- 查询存在但不一定存在情况
Comments:
Email questions, comments, and corrections to hi@smartisan.dev.
Submissions may appear publicly on this website, unless requested otherwise in your email.