Skip to content

【243 - 毕业总结】 #1553

@eazonshaw

Description

@eazonshaw

学习总结

概述

主要贴合脑图进行课程总结,并将课程中提到的需要重点记忆的代码模板,和各个知识点的LeetCode题目进行汇总。便于后面的思考与刷题。

  • 核心:
  1. 重在理解,避免死磕
  2. 重在练习,五遍刷题
  3. 机器思维,避免人肉

复杂度分析

时间复杂度

空间复杂度

  • 空间换时间,升维:在大多数情况下,会选择牺牲空间复杂度,来提高时间复杂度
  • 一般在算法中,更多的是考虑是否为“原地算法”,即是否需要申请额外的空间。

数组与链表

非受限线性表:指的就是不受规则限制,区别于栈和队列。

  • 数组和链表是所有数据结构的基础,基本上所有数据结构都可以基于数组和链表实现。
  • 数组和链表之间重点掌握区别,数组的查找时间复杂度是O(1),而链表的增加和删除时间复杂度为O(1)。
  • 数组:注意防止越界
  • 链表:单链表、双向链表、循环链表、静态链表(借助数组,伴随向后继节点的指针)

LeetCode

Array

Linked

栈和队列

受限线性表:需要满足一定的规则,即先进后出或者先进先出等。

  • 栈和队列的重点是掌握其在特殊场合下的应用。
  • 栈:先进后出,FILO。应用:浏览器前进后退、括号匹配、表达式计算。
  • 队列:先进先出,FIFO。
  • 队列的拓展:双端队列(两边均可入队和出队),优先队列(根据优先级来出队)。
  • Java PriorityQueue 源码

LeetCode

Stack

Queue

哈希表、映射、集合

  • 哈希表:又称散列表。重点需要注意哈希冲突,设计好的哈希函数可以减少重复性,但不能完全避免哈希冲突。常用拉链表(散列表+链表)解决哈希冲突,如HashMap。
  • 映射:Map。K/V键值对,key不重复
  • 集合:Set。key不重复

LeetCode

二叉树、二叉搜索树

  • 顺序和链式结构都可以实现。
  • 遍历方式:广度优先遍历(BFS)、深度优先遍历(DFS);DFS分为前序遍历(根左右)、中序遍历(左根右)、后序遍历(左右根)。重点掌握所有的模板。
  • 分类:完全二叉树(除了叶子节点外,其余节点的度均为2的二叉树),满二叉树(最后一层全是叶子节点的完全二叉树),二叉搜索树等。
  • 二叉搜索树的中序遍历即为有序遍历。
  • 自平衡二叉搜索树(AVL)的动图演示

LeetCode

递归

  • 递归模板
  • 核心:递归四部曲,终止条件、执行当前层逻辑、下坠、清理当前层的状态。
public void recur(int level, int param) { 

  // terminator 
  if (level > MAX_LEVEL) { 
    // process result 
    return; 
  } 

  // process current logic 
  process(level, param); 

  // drill down 
  recur( level: level + 1, newParam); 

  // restore current status 
 
}

LeetCode

分治、回溯

分治代码模板

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, …)
	
  # revert the current level states

LeetCode

BFS、DFS

  • BSF模板
  • 核心:维护一个queue队列,建立一个访问记录visited集合,有时候还需要在节点处记录当前的层数level。
def BFS(graph, start, end):
    visited = set()
	queue = [] 
	queue.append([start]) 

	while queue: 
		node = queue.pop() 
		visited.add(node)

		process(node) 
		nodes = generate_related_nodes(node) 
		queue.push(nodes)

	# other processing work 
	...
  • DFS模板
  • 核心:DFS在非递归写法时,是维护一个stack栈
//递归写法
visited = set() 

def dfs(node, visited):
    if node in visited: # terminator
    	# already visited 
    	return 

	visited.add(node) 

	# process current node here. 
	...
	for next_node in node.children(): 
		if next_node not in visited: 
			dfs(next_node, visited)
			
//非递归写法
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 
	...

LeetCode

贪心算法

  • 贪心算法是弱化版的动态规划。很多时候都得先判断是否能用贪心算法解决,再使用贪心算法。如最经典的找零问题,在保证大的币种肯定是小的币种的倍数的情况下,可以利用贪心算法解决问题。

LeetCode

柠檬水找零

二分查找

left, right = 0, len(array) - 1 
while left <= right: 
	  mid = (left + right) / 2 
	  if array[mid] == target: 
		    # find the target!! 
		    break or return result 
	  elif array[mid] < target: 
		    left = mid + 1 
	  else: 
		    right = mid - 1

注意,一般防止越界,第三行代码会改写为mid = right + (left - right) >> 1

LeetCode

动态规划

动态规划在大多数情况下和记忆化递归的时间复杂度相近,如经典的爬楼梯问题,既可以使用斐波那契数列,f(n) = f(n-1) + f(n-2),加上缓存cache的记忆化递归的方式求解,也可以使用动态规划,利用dp方程,dp[i] = dp[i-1] + dp[i-2]进行求解。

  • 自底向上递推
  • 核心:状态转移方程最近重复子问题最优子结构

LeetCode

字典树

  • 字典树,又称前缀树、Trie树。主要应用于搜索时前缀单词提示。
  • 核心:理解和记忆Trie树的代码模板
  • Trie树模板
class Trie(object):
  
	def __init__(self): 
		self.root = {} 
		self.end_of_word = "#" 
 
	def insert(self, word): 
		node = self.root 
		for char in word: 
			node = node.setdefault(char, {}) 
		node[self.end_of_word] = self.end_of_word 
 
	def search(self, word): 
		node = self.root 
		for char in word: 
			if char not in node: 
				return False 
			node = node[char] 
		return self.end_of_word in node 
 
	def startsWith(self, prefix): 
		node = self.root 
		for char in prefix: 
			if char not in node: 
				return False 
			node = node[char] 
		return True

LeetCode

并查集

  • 并查集,主要应用于解决站队问题,即朋友圈问题。
  • 核心:熟悉并查集的基本操作,即初始化、查询、合并。
  • 并查集模板
class UnionFind { 
	private int count = 0; 
	private int[] parent; 
	public UnionFind(int n) { 
		count = n; 
		parent = new int[n]; 
		for (int i = 0; i < n; i++) { 
			parent[i] = i;
		}
	} 
	public int find(int p) { 
		while (p != parent[p]) { 
			parent[p] = parent[parent[p]]; 
			p = parent[p]; 
		}
		return p; 
	}
	public void union(int p, int q) { 
		int rootP = find(p); 
		int rootQ = find(q); 
		if (rootP == rootQ) return; 
		parent[rootP] = rootQ; 
		count--;
	}
}

LeetCode

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions