这篇博客记录 leetcode中 二叉树有关的问题
先是三大遍历
即:
前序遍历,总是先访问当前节点,再左子,最后右子
中序遍历,总是先访问左子,再当前节点,最后右子
后序遍历,总是先访问左子,再右子,最后当前节点
条件反射的记住非递归全都是用栈,后序遍历多了一个节点记录访问的过程。
每种遍历我都用递归和非递归实现了一遍,每种方式都得会才行
144. Binary Tree Preorder Traversal
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
// 迭代的方法
// List<Integer> list = new ArrayList<Integer>() ;
// Stack<TreeNode> stack = new Stack<TreeNode>() ;
// if(root == null){
// return list ;
// }
// stack.push(root);
// 先访问根结点,在循环之前就出栈,所以不用在循环里面判断根结点是否为空
// while(!stack.isEmpty()){
// TreeNode node = stack.pop() ;
// list.add(node.val);
// if(node.right != null){
// stack.push(node.right) ;
// }
// if(node.left != null){
// stack.push(node.left) ;
// }
// }
// return list ;
// 递归的方法
// List<Integer> list = new ArrayList<Integer>() ;
// traversal(root , list);
// return list ;
// }
// private void traversal(TreeNode root , List<Integer> list){
// if(root == null){
// return ;
// }
// list.add(root.val) ;
// traversal(root.left , list) ;
// traversal(root.right , list) ;
//分治的方法
List<Integer> list = new ArrayList<Integer>() ;
if(root == null){
return list ;
}
// 分
List<Integer> left = preorderTraversal(root.left);
List<Integer> right = preorderTraversal(root.right);
// 治
list.add(root.val) ;
list.addAll(left) ;
list.addAll(right) ;
return list ;
}
}
94. Binary Tree Inorder Traversal
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<Integer>();
Stack<TreeNode> stack = new Stack<TreeNode>();
if(root ==null){
return list ;
}
TreeNode cur = root ;
// 注意和先序遍历不一样,这里不能先把根结点先push,要加到while里面判断,
while(!stack.isEmpty() || cur != null){
while(cur != null){
stack.push(cur) ;
cur = cur.left ;
}
if(!stack.isEmpty()){
cur = stack.pop() ;
list.add(cur.val) ;
cur = cur.right ;
}
}
return list ;
// 分治法
// List<Integer> list = new ArrayList<Integer>() ;
// if(root == null){
// return list ;
// }
// List<Integer> l = inorderTraversal(root.left) ;
// List<Integer> r = inorderTraversal(root.right) ;
// list.addAll(l);
// list.add(root.val);
// list.addAll(r);
// return list ;
}
}
后序遍历最难的一个一定要记清楚了多用了一个cur节点
145. Binary Tree Postorder Traversal
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
// List<Integer> list = new ArrayList<Integer>() ;
// if(root == null){
// return list ;
// }
// List<Integer> l = postorderTraversal(root.left);
// List<Integer> r = postorderTraversal(root.right);
// list.addAll(l) ;
// list.addAll(r) ;
// list.add(root.val) ;
// return list ;
// 以下下思路是我百度的,我想不出来~~~~~~~
// (1)如果pre的左孩子或者右孩子是cur,那么说明遍历在往下走,按访问顺序继续,即如果有左孩子,则是左孩子进栈,否则如果有右孩子,则是右孩子进栈,如果左右孩子都没有,则说明该结点是叶子,可以直接访问并把结点出栈了。
// (2)如果反过来,cur的左孩子是pre,则说明已经在回溯往上走了,但是我们知道后序遍历要左右孩子走完才可以访问自己,所以这里如果有右孩子还需要把右孩子进栈,否则说明已经到自己了,可以访问并且出栈了。
// (3)如果cur的右孩子是pre,那么说明左右孩子都访问结束了,可以轮到自己了,访问并且出栈即可。
List<Integer> list = new ArrayList<Integer>() ;
Stack<TreeNode> stack = new Stack<TreeNode>() ;
TreeNode cur = root ;
// 追逐指针
TreeNode pre = null ;
if(root == null){
return list ;
}
stack.push(cur) ;
while(!stack.isEmpty()){
cur = stack.peek();
// 如果pre的左孩子或者右孩子是cur,那么说明遍历在往下走,按访问顺序继续,即如果有左孩子,则是左孩子进栈,否则如果有右孩子,则是右孩子进栈,如果左右孩子都没有,则说明该结点是叶子,可以直接访问并把结点出栈了。
if(pre == null || pre.left == cur || pre.right == cur){
if(cur.left != null){
stack.push(cur.left);
}
else if(cur.right != null){
stack.push(cur.right) ;
}
}
// 如果反过来,cur的左孩子是pre,则说明已经在回溯往上走了,但是我们知道后序遍历要左右孩子走完才可以访问自己,所以这里如果有右孩子还需要把右孩子进栈,否则说明已经到自己了,可以访问并且出栈了。
else if(cur.left == pre){
if(cur.right != null){
stack.push(cur.right) ;
}
}
// 如果cur的右孩子是pre,那么说明左右孩子都访问结束了,可以轮到自己了,访问并且出栈即可。
else{
list.add(cur.val);
stack.pop() ;
}
pre = cur ;
}
return list ;
}
}
104. Maximum Depth of Binary Tree求二叉树的最大深度,用分治法,先求左右子树的最大深度然后再把最深的一个加一就是结果
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
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 ;
}
}
110. Balanced Binary Tree 判断一个二叉树是否是平衡的,也是分治法
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public boolean isBalanced(TreeNode root) {
return MaxDepth(root) != -1;
}
private int MaxDepth(TreeNode root){
if(root == null){
return 0;
}
// 分治法分别看左右子树是否是平衡的
int left = MaxDepth(root.left);
int right = MaxDepth(root.right);
// 如果左右子树不平衡或者 左右子树高度差大于一,就认为是不平衡的
if(left == -1 || right == -1 || Math.abs(left - right) > 1){
// 设不平衡时返回 -1
return -1;
}
// 其余情况返回树的高度
return Math.max(left , right) + 1;
}
}
124. Binary Tree Maximum Path Sum这道题比较难,具体的分析看我代码的zhu sh
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
// 分治法
//因为要传递两个参数,所以要新建一个类
private class help{
int singlePath ;
int maxPath;
help(int singlePath , int maxPath){
this.singlePath = singlePath;
this.maxPath = maxPath;
}
}
private help helper(TreeNode root){
if(root == null){
//递归终止条件,0表示一个点都没取到,Integer.MIN_VALUE表示一条路径都取不到;
return new help (0 , Integer.MIN_VALUE);
}
//divide
help left = helper(root.left);
help right = helper(root.right);
//conquer
// 有三种情况,一种是左边的单路路径最长,一种是右边的单路路径最长,一种是横跨左右加根节点的路径最长
//计算最长的单路路径
int singlePath = Math.max(left.singlePath , right.singlePath) + root.val;
//和0比较小于零说明是负数就不要
singlePath = Math.max(singlePath , 0);
//计算左右子树的最长路径
int maxPath = Math.max(left.maxPath , right.maxPath);
//总共的最长路径和左右子树的最长路径相比较
maxPath = Math.max(maxPath , left.singlePath + right.singlePath + root.val);
return new help(singlePath , maxPath);
}
public int maxPathSum(TreeNode root) {
help help = helper(root);
return help.maxPath;
}
}
235 . Lowest Common Ancestor of a Binary Search Tree
这道题注意是二叉搜索树,应该先百度什么是二叉搜索树,利用他的性质
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/点击打开链接
public class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root == null || p == null || q == null)
return null;
// 说明在左子树
if(root.val > p.val && root.val > q.val)
return lowestCommonAncestor(root.left , p , q);
// 说明在右子树
if(root.val < p.val && root.val < q.val)
return lowestCommonAncestor(root.right , p , q);
return root;
}
}
236. Lowest Common Ancestor of a Binary Tree这个题是上个题的升级版,注意不能用二叉搜索树的性质!
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// 左右子树探索时发现目标节点,则通过返回值标记
if(root == null || p == root || q == root) {
return root;
}
// 查看左子树中是否有目标结点,没有为null
TreeNode l = lowestCommonAncestor(root.left,p,q);
// 查看右子树中是否有目标结点,没有为null
TreeNode r = lowestCommonAncestor(root.right,p,q);
//都不为空,说明做右子树都有目标结点,则公共祖先就是本身
if(l!= null && r!= null) {
return root;
}
// 其他情况,则要继续向下标记,显示此节点下边有目标节点
return l != null?l:r;
}
}
102. Binary Tree Level Order Traversal基本题型bfs 用一个队列来实现
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> list = new LinkedList<List<Integer>>() ;
// 用队列来保存访问顺序
Queue<TreeNode> queue = new LinkedList<TreeNode>() ;
if(root == null){
return list ;
}
// 根节点先入队
queue.offer(root);
// 队列不为空循环继续
while(!queue.isEmpty()){
// 当前队列的size()就是上一层的节点数注意这是重点
int size = queue.size() ;
// 每一层的元素存到一个队列里面
List<Integer> levelList = new LinkedList<Integer>() ;
for(int i = 0 ; i < size ; i ++){
if(queue.peek().left != null){
// 给下一层做准备
queue.add(queue.peek().left) ;
}
// 注意没有else
if(queue.peek().right != null){
queue.add(queue.peek().right) ;
}
levelList.add(queue.poll().val) ;
}
list.add(levelList) ;
}
return list ;
}
}
107. Binary Tree Level Order Traversal II 这就是上个题的变形,将得到的队列反转就好了
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> list = new LinkedList<List<Integer>>() ;
Queue<TreeNode> queue = new LinkedList<TreeNode>() ;
if(root == null){
return list ;
}
queue.add(root) ;
while(!queue.isEmpty()){
int size = queue.size() ;
List<Integer> levelList = new LinkedList<Integer>() ;
for(int i = 0 ; i < size ; i ++){
if(queue.peek().left != null){
queue.add(queue.peek().left) ;
}
if(queue.peek().right != null){
queue.add(queue.peek().right) ;
}
levelList.add(queue.poll().val) ;
}
list.add(0 ,levelList) ;
}
return list ;
}
}
103. Binary Tree Zigzag Level Order Traversalbfs变形版,具体方法看注释
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
// 主要思想就是奇数层正常的广度优先遍历 偶数层将遍历的链表先翻转再加入到list中
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> list = new LinkedList<List<Integer>>() ;
Queue<TreeNode> queue = new LinkedList<TreeNode>() ;
if(root == null){
return list ;
}
// 用来判断现在是奇数层还是偶数层 ;
int a = 1 ;
queue.add(root);
while(!queue.isEmpty()){
List<Integer> levelList = new LinkedList<Integer>() ;
int size = queue.size() ;
for(int i = 0 ; i < size ; i ++){
if(queue.peek().left != null){
queue.add(queue.peek().left) ;
}
if(queue.peek().right != null){
queue.add(queue.peek().right) ;
}
// 判断奇偶,奇数正常,偶数反转 ;
if(a % 2 != 0){
levelList.add(queue.poll().val);
}else{
levelList.add(0 , queue.poll().val) ;
}
}
a ++ ;
list.add(levelList) ;
}
return list ;
}
}
98. Validate Binary Search Tree判断一个树是否是二叉搜索树,二叉搜索树的中序遍历是一个升序的list,先进行中序遍历然后,再判断是否是升序的
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
// 二叉查找树的中序遍历应该是升序的,思路就是先进行中序遍历,在判断遍历后得到的链表是不是升序的;
public class Solution {
public boolean isValidBST(TreeNode root) {
List<Integer> newList = inOrder(root) ;
int size = newList.size() ;
// 判断后一位是否大于前一位
for(int i = 0 ; i < size - 1 ; i++){
if(newList.get(i) >= newList.get(i + 1)){
return false ;
}
}
return true ;
}
// 先中序遍历
private List inOrder(TreeNode root){
List<Integer> list = new LinkedList<Integer>() ;
if(root == null){
return list ;
}
List<Integer> left = inOrder(root.left) ;
List<Integer> right = inOrder(root.right) ;
list.addAll(left) ;
list.add(root.val) ;
list.addAll(right) ;
return list ;
}
}