二叉树的理论基础
-
关于二叉树,你该了解这些!:二叉树的种类、存储方式、遍历方式、定义方式
public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() { } TreeNode(int val) { this.val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this.val = val; this.left = left; this.right = right; } }
-
二叉树的遍历方式
1 深度优先遍历(栈模拟)–DFS
图的搜索有两种方式,一种是深度优先搜索(Depth-First-Search),另一种是广度优先搜索(Breadth-First-Search)。
如果需要搜索整颗二叉树,那么递归函数就不要返回值,如果要搜索其中一条符合条件的路径,递归函数就需要返回值,因为遇到符合条件的路径了就要及时返回。
144 - 二叉树:前序递归法—中左右
//方法一:递归法
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
preorder(root,res);
return res;
}
public void preorder(TreeNode root, List<Integer> res){
if (root == null){
return;
}
res.add(root.val);
preorder(root.left,res);
preorder(root.right,res);
}
}
//方法二:迭代法
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode node = root;
while (!stack.isEmpty() || node != null) {
while (node != null) {
res.add(node.val);
stack.push(node);
node = node.left;
}
node = stack.pop();
node = node.right;
}
return res;
}
}
复杂度分析
时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。
94 - 二叉树:中序迭代法—左中右
//方法一:递归法
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
inorder(root, res);
return res;
}
public void inorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
inorder(root.left, res);
res.add(root.val);
inorder(root.right, res);
}
}
//方法二:迭代法
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
Deque<TreeNode> stk = new LinkedList<TreeNode>();
while (root != null || !stk.isEmpty()) {
while (root != null) {
stk.push(root);
root = root.left;
}
root = stk.pop();
res.add(root.val);
root = root.right;
}
return res;
}
}
复杂度分析
时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。
145 - 二叉树:后序迭代法—左右中
-
//方法一:递归法 class Solution { public List<Integer> postorderTraversal(TreeNode root) { List<Integer> res = new ArrayList<>(); preorder(root,res); return res; } public void preorder(TreeNode root, List<Integer> res){ if (root == null){ return; } preorder(root.left,res); preorder(root.right,res); res.add(root.val); } } //方法二:迭代法 class Solution { public List<Integer> postorderTraversal(TreeNode root) { LinkedList<Integer> result = new LinkedList<>(); Stack<TreeNode> stack = new Stack<>(); while (root != null || !stack.isEmpty()) { if (root != null) { stack.push(root); result.addFirst(root.val); root = root.right; } else { root = stack.pop(); root = root.left; } } return result; } }
复杂度分析
时间复杂度:O(n),其中 n 是二叉树的节点数。每一个节点恰好被遍历一次。
空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(logn),最坏情况下树呈现链状,为 O(n)。
2 广度优先遍历(队列模拟)–BFS
层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。
需要借用一个辅助数据结构即队列来实现,「队列先进先出,符合一层一层遍历的逻辑,而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。」
102 - 二叉树的层序遍历
/**
* 先将根节点放到队列中,然后不断遍历队列。
* 首先拿出根节点,如果左子树/右子树不为空,就将他们放入队列中. 第一遍处理完后,根节点已经从队列中拿走了,而根节点的两个孩子已放入队列中了
*
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null)
return new ArrayList<List<Integer>>();
List<List<Integer>> res = new ArrayList<List<Integer>>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
//将根节点放入队列中,然后不断遍历队列
queue.offer(root);
while (queue.size() > 0){
//获取当前队列的长度,这个长度相当于 当前这一层的节点个数
int size = queue.size();
ArrayList<Integer> tmp = new ArrayList<Integer>();
//将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中
//如果节点的左/右子树不为空,也放入队列中
for (int i = 0; i < size ;i++){
TreeNode node = queue.poll();
tmp.add(node.val);
if (node.left != null){
queue.offer(node.left);
}
if (node.right != null){
queue.offer(node.right);
}
}
//将临时list加入最终返回结果中
res.add(tmp);
}
return res;
}
}
复杂度分析
时间复杂度: O(n)
空间复杂度:O(n)
107 - 二叉树的层序遍历2
通过队列模拟,返回其节点值自底向上的层序遍历
得到二叉树的层序遍历后,反转result数组就可以了
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
if (root == null)
return new ArrayList<List<Integer>>();
List<List<Integer>> res = new ArrayList<List<Integer>>();
Queue<TreeNode> queue = new LinkedList<TreeNode>();
//将根节点放入队列中,然后不断遍历队列
queue.offer(root);
while (queue.size() > 0){
//获取当前队列的长度,这个长度相当于 当前这一层的节点个数
int size = queue.size();
ArrayList<Integer> tmp = new ArrayList<Integer>();
//将队列中的元素都拿出来(也就是获取这一层的节点),放到临时list中
//如果节点的左/右子树不为空,也放入队列中
for (int i = 0; i < size ;i++){
TreeNode node = queue.poll();
tmp.add(node.val);
if (node.left != null){
queue.add(node.left);
}
if (node.right != null){
queue.add(node.right);
}
}
//将临时list加入最终返回结果中,每次得到的数据都插在头上 arraylist.add(int index,E element)
res.add(0,tmp);
}
return res;
}
}
复杂度分析
时间复杂度: O(n)
空间复杂度:O(n)
199-二叉树的右视图
给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值
思路:层序遍历的时候,判断是否遍历到单层的最后面的元素,如果是,就放进result数组中,随后返回result就可以了。
/**
* 一、BFS
* 思路: 利用 BFS 进行层次遍历,记录下每层的最后一个元素。
*/
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()){
int size = queue.size();
for (int i = 0; i < size ;i++){
TreeNode node = queue.poll();
if (node.left != null){
queue.offer(node.left);
}
if (node.right != null){
queue.offer(node.right);
}
if (i == size - 1){
//将当前层的最后一个节点放入结果列表
res.add(node.val);
}
}
}
return res;
}
}
//DFS
//思路: 我们按照 「根结点 -> 右子树 -> 左子树」 的顺序访问,就可以保证每层都是最先访问最右边的节点的。
class Solution {
List<Integer> res = new ArrayList<>();
public List<Integer> rightSideView(TreeNode root) {
dfs(root, 0); // 从根节点开始访问,根节点深度是0
return res;
}
private void dfs(TreeNode root, int depth) {
if (root == null) {
return;
}
// 先访问 当前节点,再递归地访问 右子树 和 左子树。
if (depth == res.size()) {
// 如果当前节点所在深度还没有出现在res里,说明在该深度下当前节点是第一个被访问的节点,因此将当前节点加入res中。
res.add(root.val);
}
depth++;
dfs(root.right, depth);
dfs(root.left, depth);
}
}
复杂度分析
时间复杂度: O(n)
空间复杂度:O(n)
637-二叉树的层平均值
给定一个非空二叉树, 返回一个由每层节点平均值组成的数组。
思路:本题就是层序遍历的时候把一层求个总和再取一个均值。
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> qu