深度优先遍历:按照根节点相对于左右子节点的访问先后来划分

前序 Pre-Order Traversal: 先访问根结点 再访问子树

中序 In-Order Traversal: 先访问左(右)子树,再访问根结点,最后访问右(左)子树

后序 Post-Order Traversal: 先访问子树,再访问根结点

快速排序是二叉树的前序遍历

快速排序的逻辑是,若要对 nums[lo..hi] 进行排序,我们先找一个分界点 p,通过交换元素使得 nums[lo..p-1] 都小于等于 nums[p],且 nums[p+1..hi] 都大于 nums[p],然后递归地去 nums[lo..p-1] 和 nums[p+1..hi] 中寻找新的分界点,最后整个数组就被排序

func quickSort(nums []int, low, high int) {
	// 前序遍历位置
	p := partition(nums, low, high) // 通过交换元素构建分界点 p
	quickSort(nums, low, p-1)
	quickSort(nums, p+1, high)
}

归并排序是二叉树的后序遍历

归并排序的逻辑,若要对 nums[lo..hi] 进行排序,我们先对 nums[lo..mid] 排序,再对 nums[mid+1..hi] 排序,最后把这两个有序的子数组合并

func mergeSort(nums []int, low, high int) {
	mid := (low + high) / 2
	mergeSort(nums, low, mid)
	mergeSort(nums, mid+1, high)
	// 后序遍历位置 合并两个排好序的子数组
	merge(nums, low, mid, high)
}

只要涉及递归,都可以抽象成二叉树的问题

我们先把题目要求细化,搞清楚 root 结点应该做什么,最后交给前/中/后序遍历框架,不要跳进递归细节

226. Invert Binary Tree

		 4
   /   \\
  2     7
 / \\   / \\
1   3 6   9

关键思路在于我们发现翻转整棵树就是交换每个结点的左右子结点,于是把交换的逻辑放在前/后序遍历的位置。二叉树的问题要细化成每个结点需要做的子操作

func invertTree(root *TreeNode) *TreeNode {
	if root == nil {
		return nil
	}
	// 前序遍历位置 交换左右子结点
	tmp := root.Left
	root.Left = root.Right
	root.Right = tmp
	
	invertTree(root.Left)
	invertTree(root.Right)

	return root
}

116. Populating Next Right Pointers in Each Node