目录
5、102. 二叉树的层序遍历 - 力扣(LeetCode)
七、二叉树遍历_牛客题霸_牛客网 (nowcoder.com)
八、236. 二叉树的最近公共祖先 - 力扣(LeetCode)
九、二叉搜索树与双向链表_牛客题霸_牛客网 (nowcoder.com)
十、105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
十一、106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

我们考虑它相同和不相同的情况,再用递归遍历:

完整代码:
- public boolean isSameTree(TreeNode p, TreeNode q) {
- if(p == null && q != null || p != null && q == null){
- return false;
- }
- if (p == null && q == null){
- return true;
- }
- if(p.val != q.val){
- return false;
- }
- return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
- }


这道题,我们可以直接用上一道题的代码,其思路如下:
完整代码:
- class Solution {
- //时间复杂度为:n * m
- public boolean isSameTree(TreeNode p, TreeNode q) {
- if(p == null && q != null || p != null && q == null) {
-
- return false;
- }
- if(p == null && q == null) {
- return true;
- }
- if(p.val != q.val) {
- return false;
- }
- return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
- }
- public boolean isSubtree(TreeNode root, TreeNode subRoot) {
- if (root == null || subRoot == null){
- return false;
- }
- if (isSameTree(root,subRoot)){
- return true;
- }
- if(isSubtree(root.left,subRoot)){
- return true;
- }
- if(isSubtree(root.right,subRoot)){
- return true;
- }
- return false;
- }
- }

思路:

完整代码:
- class Solution {
- //时间复杂度为:n * n
- int getHeight(TreeNode root){
- if (root == null){
- return 0;
- }
- int leftTree = getHeight(root.left);
- int rightTree = getHeight(root.right);
- return leftTree > rightTree ? leftTree+1 : rightTree+1;
- }
- public boolean isBalanced(TreeNode root) {
- if(root == null){
- return true;
- }
- int leftHeight = getHeight(root.left);
- int rightHeight = getHeight(root.right);
- return Math.abs(leftHeight-rightHeight) <= 1
- && isBalanced(root.left)
- && isBalanced(root.right);
- }
- }
上面的这种解法的时间复杂度是O(n^2),会出现大量的的重复计算,当计算根结点的左子树高度时,递归到数字九时返回一个2就已经说明了该树不平衡,所以我们从下向上计算高度时顺便判断一下,这样的话时间复杂度就是O(n):
- class Solution {
- int getHeight(TreeNode root){
- if (root == null){
- return 0;
- }
- int leftHeight = getHeight(root.left);
- int rightHeight = getHeight(root.right);
- if(leftHeight >= 0 && rightHeight >= 0 && Math.abs(leftHeight - rightHeight) <= 1){
- return Math.max(leftHeight,rightHeight) + 1;
- }else{
- //返回-1 就说明已经出现了不平衡
- return -1;
- }
- }
- public boolean isBalanced(TreeNode root) {
- if(root == null){
- return true;
- }
- return getHeight(root) >= 0;
- }
- }

思路就是判断root的左右子树是否对称:左子树的右树和右子树的左树是否相同:
- class Solution {
- public boolean isSymmetric(TreeNode root) {
- if(root == null) {
- return true;
- }
- return isSymmetricChild(root.left,root.right);
- }
- private boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {
- //判断左子树的右树和右子树的左树是否相同.
- if (leftTree == null && rightTree != null || leftTree != null && rightTree == null){
- return false;
- }
- //是否都为空
- if (leftTree == null && rightTree == null){
- return true;
- }
- //判断val值
- if (leftTree.val != rightTree.val){
- return false;
- }
- //进行递归左子树的右树和右子树的左树
- return isSymmetricChild(leftTree.left, rightTree.right) &&
- isSymmetricChild(leftTree.right, rightTree.left);
- }
- }

思路:

完整代码:
- class Solution {
- public List
> levelOrder(TreeNode root) {
- List
> ret = new ArrayList>();
- if(root == null){
- return ret;
- }
- Queue
queue = new LinkedList(); - queue.offer(root);
- while(!queue.isEmpty()){
- List
leve = new ArrayList(); - int queue_size = queue.size();
- for(int i = 0; i < queue_size; i++){
- TreeNode node = queue.poll();
- leve.add(node.val);
- if(node.left != null){
- queue.offer(node.left);
- }
- if(node.right != null){
- queue.offer(node.right);
- }
- }
- ret.add(leve);
- }
- return ret;
- }
- }
思路:


完整代码:
- boolean isCompleteTree(TreeNode root){
- if (root == null){
- return true;
- }
- Queue
queue = new LinkedList<>(); - queue.offer(root);
- while (!queue.isEmpty()){
- TreeNode cur = queue.poll();
- if (cur != null){
- queue.offer(cur.left);
- queue.offer(cur.right);
- }else {
- break;
- }
- }
- while (!queue.isEmpty()){
- TreeNode cur = queue.peek();
- if (cur != null){
- //不是完全二叉树
- return false;
- }else {
- queue.poll();
- }
- }
- return true;
- }

- import java.util.*;
-
- public class Main {
- class TreeNode{
- public char val;
- public TreeNode left;
- public TreeNode right;
- public TreeNode(char val){
- this.val = val;
- }
- }
- public int i = 0;
- //创建树
- public TreeNode createTree(String s){
- TreeNode root = null;
- if (s.charAt(i) != '#'){
- root = new TreeNode(s.charAt(i));
- i++;
- root.left = createTree(s);
- root.right = createTree(s);
- }else {
- i++;
- }
- return root;
- }
- public void inorder(TreeNode root){
- if (root == null){
- return;
- }
- inorder(root.left);
- System.out.print(root.val+" ");
- inorder(root.right);
- }
- public static void main(String[] args) {
- Scanner scanner = new Scanner(System.in);
- while (scanner.hasNextLine()){
- String s = scanner.nextLine();
- Main m = new Main();
- TreeNode root = m.createTree(s);
- m.inorder(root);
- }
- }
- }
-

先列出求公共祖先会出现的情况:

分析:
完整代码:
- class Solution {
- public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
- if(root == null){
- return null;
- }
- if(root == p || root == q){
- return root;
- }
- TreeNode retleft = lowestCommonAncestor(root.left,p,q);
- TreeNode retright = lowestCommonAncestor(root.right,p,q);
- if(retleft != null && retright != null){
- return root;
- }else if(retleft != null){//都在左树
- return retleft;
- }else{
- return retright;
- }
- }
- }
当我们用栈的思想来解决这道题时,可以有:

完整代码:
- class Solution {
- //找到根结点到指定节点node之间路径上的所有结点,存储到栈中
- private boolean getPath(TreeNode root, TreeNode node, Stack
stack) { - if (root == null || node == null) {
- return false;
- }
- stack.push(root);
- if (root == node) {
- return true;
- }
- boolean ret1 = getPath(root.left, node, stack);
- if (ret1) {
- return true;
- }
- boolean ret2 = getPath(root.right, node, stack);
- if (ret2) {
- return true;
- }
- //当前根结点不是,根的左右子树都不是
- stack.pop();
- return false;
- }
-
- public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q){
- Stack
stack1 = new Stack<>(); - getPath(root,p,stack1);
- Stack
stack2 = new Stack<>(); - getPath(root,q,stack2);
- int size1 = stack1.size();
- int size2 = stack2.size();
- if(size1 > size2){
- int tmp = size1 - size2;
- while(tmp != 0){
- stack1.pop();
- tmp--;
- }
- }else{
- int tmp = size2 - size1;
- while(tmp != 0){
- stack2.pop();
- tmp--;
- }
- }
- while(!stack1.empty() && !stack2.empty()){
- if(stack1.peek() == stack2.peek()){
- return stack1.peek();
- }else{
- stack1.pop();
- stack2.pop();
- }
- }
- return null;
- }
- }

思路:
- public class Solution {
- TreeNode prev = null;
- public void ConvertChild(TreeNode root){
- if (root == null){
- return;
- }
- ConvertChild(root.left);
- root.left = prev;
- if (prev != null){
- prev.right = root;
- }
- prev = root;
- ConvertChild(root.right);
- }
- public TreeNode Convert(TreeNode pRootOfTree){
- if (pRootOfTree == null){
- return null;
- }
- ConvertChild(pRootOfTree);
- TreeNode head = pRootOfTree;
- while(head.left != null){
- head = head.left;
- }
- return head;
- }
- }

思路:

完整代码:
- class Solution {
- public int preIndex = 0;
- public TreeNode buildTreeChild(int[] preorder, int[] inorder,int inBegin,int inEnd){
- if(inBegin > inEnd){
- return null;
- }
- TreeNode root = new TreeNode(preorder[preIndex]);
- int rootIndex = findInorderIndex(inorder,preorder[preIndex],inBegin,inEnd);
- preIndex++;
- root.left = buildTreeChild(preorder,inorder, inBegin, rootIndex-1);
- root.right = buildTreeChild(preorder,inorder,rootIndex+1, inEnd);
- return root;
- }
- //找到根结点的位置
- private int findInorderIndex(int[] inorder,int val,int inBegin,int inEnd){
- for(int i = inBegin; i <= inEnd; i++){
- if(inorder[i] == val){
- return i;
- }
- }
- return -1;
- }
- public TreeNode buildTree(int[] preorder, int[] inorder) {
- return buildTreeChild(preorder,inorder,0,inorder.length-1);
- }
- }
同理这道题也是一样的道理:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
只不过变成了后序序列倒着是根结点:
- class Solution {
- public int postIndex;
- public TreeNode buildTreeChild(int[] postorder, int[] inorder,int inBegin,int inEnd){
- if(inBegin > inEnd){
- return null;
- }
- TreeNode root = new TreeNode(postorder[postIndex]);
- int rootIndex = findInorderIndex(inorder,postorder[postIndex],inBegin,inEnd);
- postIndex--;
- root.right = buildTreeChild(postorder,inorder,rootIndex+1, inEnd);
- root.left = buildTreeChild(postorder,inorder, inBegin, rootIndex-1);
-
- return root;
- }
- private int findInorderIndex(int[] inorder,int val,int inBegin,int inEnd){
- for(int i = inBegin; i <= inEnd; i++){
- if(inorder[i] == val){
- return i;
- }
- }
- return -1;
- }
- public TreeNode buildTree(int[] inorder,int[] postorder) {
- postIndex = postorder.length-1;
- return buildTreeChild(postorder,inorder,0,inorder.length-1);
- }
- }

思路:
每颗小子树走完都会加一个右括号,当然除了根结点剩下的结点都先加一个左括号,变美丽树,并将其打印出来:
- class Solution {
- public String tree2str(TreeNode root) {
- //通过StringBuilder修改字符串
- StringBuilder sb = new StringBuilder();
- tree2strChild(root,sb);
- return sb.toString();
- }
- private void tree2strChild(TreeNode t,StringBuilder sb){
- if(t == null){
- return;
- }
- sb.append(t.val);
- //左子树不为空就加个左括号
- if(t.left != null){
- sb.append("(");
- tree2strChild(t.left,sb);
- sb.append(")");
- }else{
- if(t.right == null){
- return;
- }else{
- sb.append("()");
- }
- }
- if(t.right == null){
- return;
- }else{
- sb.append("(");
- tree2strChild(t.right,sb);
- sb.append(")");
- }
- }
- }
前序遍历思路:
创建一个栈,将根结点入栈并打印,再遍历root.left,当结点左右子树为空时就出栈并赋值给top记录下来,再继续遍历root.right:
- class Solution {
- public List
preorderTraversal(TreeNode root){ - List
ret = new ArrayList<>(); - Stack
stack = new Stack<>(); - TreeNode cur = root;
- while (cur != null || !stack.isEmpty()) {
- while (cur != null) {
- stack.push(cur);
- System.out.println(cur.val + " ");
- ret.add(cur.val);
- cur = cur.left;
- }
- TreeNode top = stack.pop();
- cur = top.right;
- }
- return ret;
- }
- }
中序遍历同理:
- class Solution {
- public List
inorderTraversal(TreeNode root) { - List
list = new ArrayList<>(); - Stack
stack = new Stack<>(); - TreeNode cur = root;
- while (cur != null || !stack.isEmpty()) {
- while (cur != null) {
- stack.push(cur);
- cur = cur.left;
- }
- TreeNode top = stack.pop();
- System.out.println(cur.val + " ");
- list.add(top.val);
- cur = top.right;
- }
- return list;
- }
- }
后序遍历:
- class Solution {
- public List
postorderTraversal(TreeNode root) { - List
list = new ArrayList<>(); - Stack
stack = new Stack<>(); - TreeNode prev = null;
- TreeNode cur = root;
- while (cur != null || !stack.isEmpty()) {
- while (cur != null) {
- stack.push(cur);
- cur = cur.left;
- }
- //不能直接弹出
- TreeNode top = stack.peek();
-
- if(top.right == null || top.right == prev){
- stack.pop();
- list.add(top.val);
- prev = top;
- }else{
- cur = top.right;
- }
- }
- return list;
- }
- }