树、二叉树
二叉树又有特殊二叉树,完全二叉树,满二叉树
因为二叉树本身就是递归型数据结构,所以很多问题都可以用递归实现
总结递归1.当做根、左子树、右子树三部分,左子树、右子树具体是什么样的不管 2.找出终止条件,就是什么时候return,return什么 3.只考虑当前这一步要完成什么功能
Solution114二叉树展开为链表、Solution111二叉树的最小深度、Solution107二叉树的层序遍历Ⅱ、Solution104二叉树的最大深度、Solution102二叉树的层序遍历、Solution94中序遍历、Solution144前序遍历、Solution145后序遍历、
Solution114二叉树展开为链表
给你二叉树的根结点 root ,请你将它展开为一个单链表:
展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。
递归因为在操作左子树之前不能动右子树,所以用后序遍历
class Solution {
public void flatten(TreeNode root) {
if(root == null) {
return;
}
flatten(root.left);
flatten(root.right);
//临时变量储存右节点
TreeNode tmp = root.right;
root.right = root.left;
root.left = null;
while(root.right != null) {
root = root.right;
}
root.right = tmp;
}
}
迭代循环方式
class Solution {
public void flatten(TreeNode root) {
Stack<TreeNode> stack = new Stack();
while (root != null || !stack.isEmpty()){
while (root != null){
stack.push(root);
root = root.left;
}
if (!stack.isEmpty()){
TreeNode node = stack.pop();
TreeNode tmp = node.right;
node.right = node.left;
node.left = null;
while(node.right != null) node = node.right;
node.right = tmp;
root = tmp;
}
}
}
}
Solution111二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
求最小深度时将Math.max换成Math.min即可,但要注意如果根节点的左或右子树为空的话是构不成子树的。而最小深度是要求从根节点到子树的。当左或右子树为空时,不符合要求。
class Solution {
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
int left = minDepth(root.left);
int right = minDepth(root.right);
return left == 0 || right == 0 ? 1 + left + right : 1 + Math.min(left, right);
}
}
Solution107二叉树的层序遍历Ⅱ
给你二叉树的根节点
root
,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
把层序遍历Ⅰ拿来反转一下,或者如下使用LinkedList队首添加再弹出
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
//巧妙地利用了队列中的元素是按层排序的性质,
//每下一层的节点入完队,下一次的 queue.size() 就是下一层的数量
LinkedList<List<Integer>> result = new LinkedList<>();
if (root == null)
return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
List<Integer> oneLevel = new ArrayList<>();
// 每次都取出一层的所有数据
int count = queue.size();
for (int i = 0; i < count; i++) {
TreeNode node = queue.poll();
oneLevel.add(node.val);
if (node.left != null)
queue.add(node.left);
if (node.right != null)
queue.add(node.right);
}
// 每次都往队头塞
result.addFirst(oneLevel);
}
return result;
}
}
Solution104二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
递归实现比较简单
//递归
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int left = maxDepth(root.left);
int right = maxDepth(root.right);
return Math.max(left, right) + 1;
}
Solution102层序遍历
队列实现:思想为先头再左右,挨个出队,谁出队谁左右进队
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> ret = new ArrayList<List<Integer>>();
// 首先判断根节点非空
if (root == null) {
return ret;
}
// 定义队列
Queue<TreeNode> queue = new LinkedList<TreeNode>();
// 初始根节点入队
queue.add(root);
// 用于存储该层节点数值
List<Integer> level = new ArrayList<Integer>();
// 队列非空循环
while (!queue.isEmpty()) {
// 每轮出队该层的全部节点,提前记录该层节点个数,队列会变
int cur = queue.size();
for (int i = 1; i <= cur; ++i){
TreeNode node = queue.poll();
level.add(node.val);
// 如果左右孩子非空则入队
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
// 添加该层节点数值列表到结果
ret.add(level);
}
return ret;
}
}
前中后序遍历
while( 栈非空 || p 非空){
if( p 非空){}
else{}
}
照这个模板想,迭代方式一步一步来
public class Solution前后中序遍历 {
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;
}
}
//前序
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList();
Stack<TreeNode> stack = new Stack();
TreeNode cur = root;
while(cur!=null || !stack.isEmpty()){
//一直往左压入栈
while(cur!=null){
list.add(cur.val);
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
cur = cur.right;
}
return list;
}
//后序
public List<Integer> postorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
TreeNode cur = root;
TreeNode p = null;//用来记录上一节点
while(!stack.isEmpty() || cur != null){
while(cur != null){
stack.push(cur);
cur = cur.left;
}
cur = stack.peek();
if(cur.right == null || cur.right == p){
list.add(cur.val);
stack.pop();
p = cur;
cur = null;
}else{
cur = cur.right;
}
}
return list;
}
//中序
public List<Integer> inorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
while (root != null || !stack.isEmpty()) {
if (root != null) {
stack.push(root);
root = root.left;
} else {
root = stack.pop();
list.add(root.val);
root = root.right;
}
}
return list;
}
}