二叉树LeetCode刷题

二叉树LeetCode刷题

  • 1. 检查两颗树是否相同
  • 2. 另一颗树的子树
  • 3. 翻转二叉树
  • 4. 判断一颗二叉树是否是平衡二叉树
  • 5. 二叉搜索树与双向链表
  • 6. 对称二叉树
  • 7. 二叉树的构建及遍历
  • 8. 二叉树的分层遍历
  • 9. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先
  • 10. 根据一棵树的前序遍历与中序遍历构造二叉树
  • 11. 根据一棵树的中序遍历与后序遍历构造二叉树
  • 12. 二叉树创建字符串
  • 13. 二叉树前序非递归遍历实现
  • 14. 二叉树中序非递归遍历实现
  • 15. 二叉树后序非递归遍历实现

1. 检查两颗树是否相同

题目链接:100. 相同的树

解题思路:

  1. 判断两棵树的结构是否相同,若结构都不相同,则肯定不相同
  2. 判断两棵树的根节点对应的值是否相同,不相同则返回false,相同则去判断左右子树是否是相同的树

代码如下:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //判断结构是否相同
        if(p == null && q != null) {
            return false;
        }
        if(p != null && q == null) {
            return false;
        }
        if(p == null && q == null) {
            return true;
        }
        //判断值是否相同
        if(p.val == q.val) {
            //值相同则去判断左右子树是否相同
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        }
        return false;
    }
}

2. 另一颗树的子树

题目链接:572. 另一棵树的子树

解题思路:

  1. 判断原树是否与该树相同,若不相同,则递归判断原树的子树是否与该树相同
  2. 需要用到上面判断两棵树是否相同的代码

代码如下:

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null) {
            return false;
        }
        if(isSameTree(root, subRoot)) {
            return true;
        }
        return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
    }
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //判断结构是否相同
        if(p == null && q != null) {
            return false;
        }
        if(p != null && q == null) {
            return false;
        }
        if(p == null && q == null) {
            return true;
        }
        //判断值是否相同
        if(p.val == q.val) {
            //值相同则去判断左右子树是否相同
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        }
        return false;
    }
}

3. 翻转二叉树

题目链接:226. 翻转二叉树

解题思路1:

  1. 创建一个临时变量,用来交换左右子树
  2. 从树的上部依次往下交换左右子树的根节点,不断往树的深层次递归,直至为空或叶子节点

代码如下:

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) {
            return null;
        }
        //叶子节点后的节点为null,无需再交换
        if(root.left == null && root.right == null) {
            return root;
        }
        TreeNode tmp = root.left;
        root.left = root.right;
        root.right = tmp;
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

解题思路2:

  1. 利用返回值
  2. 采用后序遍历,从树的底部往顶部依次交换左右子树的根节点
  3. 需要将左右子树根节点利用返回值记录下来,便于后续对原树的左右子树节点的更改

代码如下:

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) {
            return null;
        }
        if(root.left == null && root.right == null) {
            return root;
        }
        TreeNode leftTree = invertTree(root.left);
        TreeNode rightTree = invertTree(root.right);
        root.left = rightTree;
        root.right = leftTree;
        return root; 
    }
}

4. 判断一颗二叉树是否是平衡二叉树

题目链接:110. 平衡二叉树

平衡二叉树 是指该树所有节点的左右子树的深度相差不超过 1

解题思路1:

  1. 分别获取左右子树的高度,作差,如果该树的任意一棵子树的左右子树高度差都小于等于1,则是一棵平衡树,反之则不是

代码如下:

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null) {
            return true;
        }
        int leftTreeHeight = getHeight(root.left);
        int rightTreeHeight = getHeight(root.right);
        if(Math.abs(leftTreeHeight-rightTreeHeight) > 1) {
            return false;
        }
        return isBalanced(root.left) && isBalanced(root.right);
    }
    private int getHeight(TreeNode root) {
        if(root == null) {
            return 0;
        }
        return Math.max(getHeight(root.left), getHeight(root.right)) + 1;
    }
}

该算法的时间复杂度为:O(N2)

解题思路2:

  1. 思路1是从原树往树的深层入手,会重复运算后续子树的高度,因此时间复杂度会达到O(N2);换个思路,从树的最底层往根节点入手,那么时间复杂度就会大大减少
  2. 每次将返回的左右子树高度作差,如果小于等于1,则将当前树的高度;如果大于1,则返回-1,作为标记

代码如下:

class Solution {
    public boolean isBalanced(TreeNode root) {
        return getHeight(root) >= 0;
    }
    public int getHeight(TreeNode root) {
        if(root == null) return 0;
        int leftTreeHeight = getHeight(root.left);
        if(leftTreeHeight < 0) {
            return -1;
        }
        int rightTreeHeight = getHeight(root.right);
        if(rightTreeHeight < 0) {
            return -1;
        }
        if(Math.abs(leftTreeHeight - rightTreeHeight) <= 1) {
            return Math.max(leftTreeHeight, rightTreeHeight) + 1;
        }else {
            return -1;
        }
    }
}

5. 二叉搜索树与双向链表

题目链接:二叉搜索树与双向链表

解题思路:

  1. 当二叉搜索树进行中序遍历时,得到的是一个有序的结果
  2. 那么,可以对二叉搜索树进行中序遍历,并用每个子树根节点的left指向前一个节点,right指向后一个节点,这里的前一个节点和后一个节点是转化成双向链表后,该节点的前一个节点和后一个节点

代码如下:

public class Solution {
    TreeNode prev;//记录前一个节点
    TreeNode head;//记录双向链表的头节点
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null) {
            return null;
        }
        Convert(pRootOfTree.left);

        //指向修改操作
        if(prev == null) {
            prev = pRootOfTree;
            head = pRootOfTree;
        }else {
            pRootOfTree.left = prev;
            prev.right = pRootOfTree;
            prev = pRootOfTree;
        }


        Convert(pRootOfTree.right);
        return head;
    }
}

6. 对称二叉树

题目链接:101. 对称二叉树

解题思路:

  1. 3.1是判断两棵树是否相同,现在是判断一棵树是否对称,只需将对3.1中的代码进行修改即可
  2. 判断这棵树的左子树的根节点值和右子树的根节点值是否相同,不断往深层递归

代码如下:

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null) {
            return true;
        }
        return isSameTree(root.left, root.right);
    }
    private boolean isSameTree(TreeNode p, TreeNode q) {
        if(p != null && q == null) {
            return false;
        }
        if(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.right) && isSameTree(p.right, q.left);
    }
}

7. 二叉树的构建及遍历

题目链接:KY11 二叉树遍历

解题思路:

  1. 利用先序遍历的字符串创建树,如果是#,则返回null;如果不是#,则该字符创建为根节点,再去递归去创建左子树和右子树,最后返回根节点
  2. 中序遍历这棵树

代码如下:

import java.util.Scanner;

class TreeNode {
    char val;
    TreeNode left;
    TreeNode right;
    public TreeNode(char val) {
        this.val = val;
    }
}

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            TreeNode root = createTree(str);
            inOrder(root);
        }
    }

    public static int i = 0;
    public static TreeNode createTree(String str) {
        char ch = str.charAt(i);
        if(ch == '#') {
            i++;
            return null;
        }else {
            TreeNode root = new TreeNode(ch);
            i++;
            root.left = createTree(str);
            root.right = createTree(str);
            return root;
        }
    }

    public static void inOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }
}

但是上述代码存在一点小问题:由于i是静态成员变量,在输入第一次测试用例ABC##DE#G##F###后,如果后续再输入第二组测试用例,i的值是从9开始的,这是不对的,应该是从0开始的,因此需要进行调整,调整方式有如下两种

  1. 每次循环最后将i的值更改为0
    代码如下:
import java.util.Scanner;

class TreeNode {
    char val;
    TreeNode left;
    TreeNode right;
    public TreeNode(char val) {
        this.val = val;
    }
}

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            TreeNode root = createTree(str);
            inOrder(root);
            i = 0;
        }
    }

    public static int i = 0;
    public static TreeNode createTree(String str) {
        char ch = str.charAt(i);
        if(ch == '#') {
            i++;
            return null;
        }else {
            TreeNode root = new TreeNode(ch);
            i++;
            root.left = createTree(str);
            root.right = createTree(str);
            return root;
        }
    }

    public static void inOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }
}
  1. 将静态变量i和静态方法createTree改为非静态的,那么在静态方法main中,就需要实例化Main对象,进而去调用非静态方法createTree

注:

  • 在静态方法的内部不能直接调用非静态方法,因为方法属于类而不是对象,我们可以通过自己手动new对象来在静态方法中调用

代码如下:

import java.util.Scanner;

class TreeNode {
    char val;
    TreeNode left;
    TreeNode right;
    public TreeNode(char val) {
        this.val = val;
    }
}

// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            TreeNode root = new Main().createTree(str);
            inOrder(root);
        }
    }

    public int i = 0;
    public TreeNode createTree(String str) {
        char ch = str.charAt(i);
        if(ch == '#') {
            i++;
            return null;
        }else {
            TreeNode root = new TreeNode(ch);
            i++;
            root.left = createTree(str);
            root.right = createTree(str);
            return root;
        }
    }

    public static void inOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }
}

8. 二叉树的分层遍历

题目链接:102. 二叉树的层序遍历

解题思路:

  • 大致与前面的层序遍历相同,只不过,这道题需要将每一层的元素放入一个“数组”,再将各个“数组”组和,构成一个“二维数组”

代码如下:

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> ret = new LinkedList<>();
        if(root == null) {
            return ret;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()) {
            int size = queue.size();//size即每一层的元素个数
            List<Integer> list = new LinkedList<>();
            while(size != 0) {
                TreeNode cur = queue.poll();
                list.add(cur.val);
                if(cur.left != null) {
                    queue.offer(cur.left);
                }
                if(cur.right != null) {
                    queue.offer(cur.right);
                }
                size--;
            }
            ret.add(list);
        }
        return ret;
    }
}

9. 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先

题目链接:236. 二叉树的最近公共祖先

思路1:
这两个节点无外乎有三种情况:

  1. p和q分别分布在root的左子树和右子树
    在这里插入图片描述
    这时,p和q的最近公共祖先就是root
  2. p或q与root指向同一个节点
    在这里插入图片描述
    这时,p和q的最近公共祖先就是root
  3. p和q都在root的左子树(或右子树)上
    在这里插入图片描述
    这时,往root的左子树(或右子树)递归

代码如下:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) {
            return root;
        }
        if(p == root || q == root) {
            return root;
        }
        TreeNode leftTree = lowestCommonAncestor(root.left, p, q);
        TreeNode rightTree = lowestCommonAncestor(root.right, p, q);
        if(leftTree != null && rightTree != null) {
            return root;
        }else if(leftTree == null) {
            return rightTree;
        }else {
            return leftTree;
        }
    }
}

思路2:
分别找到根节点到p和q的路径,然后求这两条路径的交点,即为p和q的最近公共祖先
在这里插入图片描述

问题的关键就是如何找到这条路径

  1. 首先需要创建一个栈来保存路径
  2. 直接将root节点放入栈种,后续若发现该节点不是路径上的节点,再将其弹出,
  3. 判断root节点是否是p节点,如果是,则直接返回true;如果不是,再分别从root节点的左子树和右子树上去找p节点
  4. 如果最后还是没有找到,说明当前的root节点不是路径上的节点,将其弹出,并返回false

找到root节点到p和q的路径后,如何求交点呢?只需将路径长的元素对应的栈,先出栈大小差值个元素,再将两个栈同时进行出栈操作,直至遇到出栈元素相同时,这时出栈的元素就是p和q最近的公共祖先

代码如下:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null) {
            return root;
        }
        Stack<TreeNode> stackP = new Stack<>();
        Stack<TreeNode> stackQ = new Stack<>();
        getPath(root, p, stackP);
        getPath(root, q, stackQ);
        int sizeP = stackP.size();
        int sizeQ = stackQ.size();
        if(sizeP > sizeQ) {
            int size = sizeP - sizeQ;
            while(size-- != 0) {
                stackP.pop();
            }
        }else {
            int size = sizeQ - sizeP;
            while(size-- != 0) {
                stackQ.pop();
            }
        }
        while(!stackP.isEmpty()) {
            if(stackP.peek() == stackQ.peek()) {
                return stackP.peek();
            }else {
                stackP.pop();
                stackQ.pop();
            }
        }
        return null;
    }
    private boolean getPath(TreeNode root, TreeNode node, Stack<TreeNode> stack) {
        if(root == null) {
            return false;
        }
        stack.push(root);
        if(root == node) {
            return true;
        }
        boolean ret = getPath(root.left, node, stack);
        if(ret) {
            return true;
        }
        ret = getPath(root.right, node, stack);
        if(ret) {
            return true;
        }
        stack.pop();
        return false;
    }
}

10. 根据一棵树的前序遍历与中序遍历构造二叉树

题目链接:105. 从前序与中序遍历序列构造二叉树

解题思路:

  1. 前序遍历是用来确定根节点的,中序遍历是用来建立左子树和右子树的
  2. 在前序遍历中,用一个变量preIndex来获取根节点;在中序遍历中,用rootIndex来标记根节点的位置,inorderBegin标记建树的起始位置,inorderEnd标记建树的终止位置
  3. 先初始化根节点,再去建立左子树和右子树,不难发现:inorderBegin = rootIndex-1,inorderEnd = rootIndex+1

于是,可以写出大体结构

TreeNode root = new TreeNode(preorder[preIndex]);

preIndex++;

//由于前序遍历顺序是:根->左->右,所以创建完根以后,应该先创建左子树,再创建右子树
root.left = buildTreeChild(preorder, preIndex, inorder, inBegin, rootIndex - 1);
root.right = buildTreeChild(preorder, preIndex, inorder, rootIndex + 1, inEnd);

再进行补充,根据思路写出的代码:

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeChild(preorder, 0, inorder, 0, inorder.length - 1);
    }

    private TreeNode buildTreeChild(int[] preorder, int preIndex, int[] inorder, int inBegin, int inEnd) {
        if (inBegin > inEnd) {
            return null;
        }
        TreeNode root = new TreeNode(preorder[preIndex]);
        int rootIndex = findVal(inorder, inBegin, inEnd, preorder[preIndex]);
        preIndex++;
        root.left = buildTreeChild(preorder, preIndex, inorder, inBegin, rootIndex - 1);
        root.right = buildTreeChild(preorder, preIndex, inorder, rootIndex + 1, inEnd);
        return root;
    }

    private int findVal(int[] inorder, int inBegin, int inEnd, int val) {
        for (int i = inBegin; i <= inEnd; i++) {
            if (inorder[i] == val) {
                return i;
            }
        }
        return -1;
    }
}

但是,这个代码存在一个特别隐蔽的问题:每次回归,preIndex的值同样会回归到原来的值,而按照我们的思路,preIndex是一直往前走的,不能回退。因此,我们需要将preIndex设置为成员变量

完善后的代码如下:

class Solution {
    public int preIndex;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTreeChild(preorder, inorder, 0, inorder.length - 1);
    }

    private TreeNode buildTreeChild(int[] preorder, int[] inorder, int inBegin, int inEnd) {
        if (inBegin > inEnd) {
            return null;
        }
        TreeNode root = new TreeNode(preorder[preIndex]);
        int rootIndex = findVal(inorder, inBegin, inEnd, preorder[preIndex]);
        preIndex++;
        root.left = buildTreeChild(preorder, inorder, inBegin, rootIndex - 1);
        root.right = buildTreeChild(preorder, inorder, rootIndex + 1, inEnd);
        return root;
    }

    private int findVal(int[] inorder, int inBegin, int inEnd, int val) {
        for (int i = inBegin; i <= inEnd; i++) {
            if (inorder[i] == val) {
                return i;
            }
        }
        return -1;
    }
}

11. 根据一棵树的中序遍历与后序遍历构造二叉树

题目链接:106. 从中序与后序遍历序列构造二叉树

解题思路大致与前面那题差不多,但也有一些区别

代码如下:

class Solution {
    public int postIndex;

    public TreeNode buildTree(int[] inorder, int[] postorder) {
        postIndex = postorder.length - 1;//后序遍历确定根,需要从后往前
        return buildTreeChild(postorder, inorder, 0, inorder.length - 1);
    }

    private TreeNode buildTreeChild(int[] postorder, int[] inorder, int inBegin, int inEnd) {
        if (inBegin > inEnd) {
            return null;
        }
        TreeNode root = new TreeNode(postorder[postIndex]);
        int rootIndex = findVal(inorder, inBegin, inEnd, postorder[postIndex]);
        postIndex--;
        
        //由于后序遍历顺序是:左->右->根,所以创建完根以后,应该先创建右子树,再创建左子树,这与前面那题是有区别的
        root.right = buildTreeChild(postorder, inorder, rootIndex + 1, inEnd);
        root.left = buildTreeChild(postorder, inorder, inBegin, rootIndex - 1);
        return root;
    }

    private int findVal(int[] inorder, int inBegin, int inEnd, int val) {
        for (int i = inBegin; i <= inEnd; i++) {
            if (inorder[i] == val) {
                return i;
            }
        }
        return -1;
    }
}

12. 二叉树创建字符串

题目链接:606. 根据二叉树创建字符串

解题思路:

  1. 先把题读懂,括号外面的表示根,第一个括号里的表示左子树,第二个括号里的表示右子树,括号里进行递归嵌套
  2. 值得注意的是,当左子树为空,右子树为空时,这时的两个括号都可以省略;当左子树不为空,右子树为空时,这时的右子树括号可以省略;当左子树为空,右子树不为空时,左子树的括号不能省略!这里需要特别注意。写代码时要注意分类讨论的条理性和严谨性
  3. 利用StringBuffer或者StringBuilder创建变量,用append方法进行字符的拼接

代码如下:

class Solution {
    public StringBuffer stringBuffer = new StringBuffer();
    public String tree2str(TreeNode root) {
        tree2strChild(root);
        return stringBuffer.toString();
    }
    private void tree2strChild(TreeNode root) {
        if(root == null) {
            return;
        }
        stringBuffer.append(root.val);
        if(root.left != null) {
            stringBuffer.append("(");
            tree2strChild(root.left);
            stringBuffer.append(")");
        }else {
            if(root.right == null) {
                return;
            }else {
                stringBuffer.append("()");
            }
        }

        if(root.right != null) {
            stringBuffer.append("(");
            tree2strChild(root.right);
            stringBuffer.append(")");
        }else {
            return;
        }
    }
}

13. 二叉树前序非递归遍历实现

题目链接:144. 二叉树的前序遍历

解题思路:

  1. 先需要利用到树中底层的节点,后用到上层的节点,所以这道题需要利用到栈
  2. 先不断向左遍历,同时将根节点放入栈和“数组”中,直至为null
  3. 再将栈顶元素出栈,并记录下来,开始遍历它的右子树
  4. 重复2和3,直至遍历完整棵树,且栈为空

代码如下:

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        if(root == null) {
            return list;
        }
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                list.add(cur.val);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            cur = top.right;
        }
        return list;
    }
}

14. 二叉树中序非递归遍历实现

题目链接:94. 二叉树的中序遍历

解题思路大致与二叉树前序非递归遍历实现相同,故不再赘述

代码如下:

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            list.add(top.val);
            cur = top.right;
        }
        return list;
    }
}

15. 二叉树后序非递归遍历实现

题目链接:145. 二叉树的后序遍历

我们可以先试着按照前面前序和中序的非递归仿写后序的非递归遍历实现

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while(cur != null || !stack.isEmpty()) {
            while(cur != null) {
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode top = stack.pop();
            if(top.right == null) {
                list.add(top.val);
            }else {
                cur = top.right;
            }
        }
        return list;
    }
}

但是这个代码是存在问题的,因为根节点是最后遍历的,在通过弹出栈顶元素来找到右节点后,后续就可能找不到根节点了,因此我们可以先peek一下,有必要时再弹出栈顶元素

修改后的代码:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        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) {
                stack.pop();
                list.add(top.val);
            }else {
                cur = top.right;
            }
        }
        return list;
    }
}

到这就完了吗?NoNoNo…我们试着举一个例子来验证一下这个代码的可行性
在这里插入图片描述
仔细分析,不难发现,代码会在节点1和节点4之间陷入死循环,这时,我们就需要用一个变量来标记4这个节点,使得当遍历节点4后,遍历节点2时,不会进入else语句(后续再次遍历节点4),而是进入if语句(将节点2弹出),这样就不会陷入死循环了,代码到此也就完善了!

完善后的代码:

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> list = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        TreeNode prev = null;//标记上一个添入元素
        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;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/890553.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

单片机IO电流倒灌

最近在某视频上看到了一个博主因为IO口电流倒灌导致ADC参考基准电压不准&#xff0c;致使ADC采样数据不准。抱着什么是IO电流倒灌的疑问&#xff0c;学习了一些文章&#xff0c;防止以后踩坑。并在下面做一下对IO口电流倒灌的总结。 目录 # 一、什么是IO电流倒灌 # 二、电流倒…

PHP商会招商项目系统一站式服务助力企业腾飞

商会招商项目系统——一站式服务&#xff0c;助力企业腾飞 &#x1f680;&#x1f4bc; &#x1f680; 开篇&#xff1a;企业成长的加速器&#xff0c;商会招商项目系统来袭 在竞争激烈的市场环境中&#xff0c;企业如何快速找到适合自己的发展路径&#xff0c;实现腾飞&…

电脑知识:适用于 Windows 10 的 PDF 编辑器列表

PDF 是一种流行的、多功能且安全的文件格式&#xff0c;用于在线共享文档。但是&#xff0c;如果没有合适的应用程序&#xff0c;查看和编辑 PDF 文件可能会变得复杂。 幸运的是&#xff0c;有很多 PDF 编辑器可以帮助您更正重要文档上的错误、填写表格、为合同添加签名、更改…

电脑基础知识:mfc110.dll丢失的解决方法

1.mfc110.dll 丢失常见原因 mfc110.dll 文件的丢失或损坏是Windows系统中常见的问题&#xff0c;它可能由多种原因引起&#xff0c;以下是一些主要的因素&#xff1a; 不完全的软件卸载 在卸载程序时&#xff0c;如果相关的 DLL 文件没有被正确移除&#xff0c;可能会导致文件…

linux 环境运行 jenkins.war包,有可能会出现字体问题,jdk版本:11 jenkins 版本:2.420

jenkins的目录&#xff1a; /usr/jenkins 启动命令 java -Djava.awt.headlesstrue sudo timedatectl set-timezone Asia/Shanghai-Xmx1024m -jar jenkins.war --httpPort8090 任意目录启动&#xff1a; nohup java -Djava.awt.headlesstrue -Xms1024m -Xmx1024m -jar /usr/j…

【C++笔试强训】如何成为算法糕手Day7

学习编程就得循环渐进&#xff0c;扎实基础&#xff0c;勿在浮沙筑高台 循环渐进Forward-CSDN博客 目录 循环渐进Forward-CSDN博客 字符串中找出连续最长的数字串 思路&#xff1a; 岛屿数量 思路&#xff1a; 深度优先遍历DFS 广度优先遍历 BFS 并查集 拼三角 思路…

学成在线——关于nacos配置优先级的坑

出错&#xff1a; 本地要起两个微服务&#xff0c;一个是content-api&#xff0c;另一个是gateway网关服务。 发现通过网关服务请求content微服务时&#xff0c;怎么请求都请求不到。 配置如下&#xff1a; content-api-dev.yaml的配置&#xff1a; server:servlet:context-p…

【华为】配置BGP协议

边界网关协议BGP是一种实现自治系统AS之间的路由可达&#xff0c;并选择最佳路由的距离矢量路由协议。BGP在不同自治系统之间进行路由转发&#xff0c;分为EBGP&#xff08;外部边界网关协议&#xff09;和IBGP&#xff08;内部边界网关协议&#xff09;两种情况。 [A]in g0/0/…

HTML(七)表格

在HTML中&#xff0c;表格的标准形式如下&#xff1a; <table></table> 使用上面的语言&#xff0c;就已经生成了一个表格&#xff0c;只不过这个表格什么都没有 那么&#xff0c;该如何让表格存在东西呢&#xff1f; 首先&#xff0c;我们需要使用到<tr> …

C++ 匿名对象(没有名字的对象,类似于临时对象)

个人主页&#xff1a;Jason_from_China-CSDN博客 所属栏目&#xff1a;C系统性学习_Jason_from_China的博客-CSDN博客 所属栏目&#xff1a;C知识点的补充_Jason_from_China的博客-CSDN博客 概念概述 用类型(实参)定义出来的对象叫做匿名对象&#xff0c;相比之前我们定义的类型…

【Windows】【DevOps】Windows Server 2022 安装ansible,基于powershell实现远程自动化运维部署 入门到放弃!

目标服务器安装openssh server参考 【Windows】【DevOps】Windows Server 2022 在线/离线 安装openssh实现ssh远程登陆powershell、scp文件拷贝-CSDN博客 注意&#xff1a;Ansible不支持Windows操作系统部署 根据官方说明&#xff1a; Windows Frequently Asked Questions —…

如何使用IntelliJ IDEA生成UML图

&#x1f3dd;️ 博主介绍 大家好&#xff0c;我是一个搬砖的农民工&#xff0c;很高兴认识大家 &#x1f60a; ~ &#x1f468;‍&#x1f393; 个人介绍&#xff1a;本人是一名后端Java开发工程师&#xff0c;坐标北京 ~ &#x1f389; 感谢关注 &#x1f4d6; 一起学习 &…

WPF 为button动态设置不同的模板

有时候需要动态的设置一些按钮的状态模板。使一个button显示不同的内容&#xff0c;比如Button未点击安装显示&#xff1a; 安装后显示&#xff1a; 可以通过设置button的content&#xff0c;通过content来设置不同的模板来实现功能&#xff0c;以下是代码&#xff1a; MainWi…

QD1-P5 HTML 段落标签(p)换行标签(br)

本节视频 www.bilibili.com/video/BV1n64y1U7oj?p5 ‍ 本节学习 HTML 标签&#xff1a; p标签 段落br标签 换行 ‍ 一、p 标签-段落 1.1 使用 p 标签划分段落 <p>段落文本</p>示例 <!DOCTYPE html> <html><head><meta charset"…

79 NAT-NAT444端口块静态映射

NAT444&#xff08;Network Address Translation 444&#xff09;是一种网络地址转换技术&#xff0c;用于将私有IP地址转换为公有IP地址&#xff0c;实现私有网络与公有网络之间的通信。 端口块静态映射是NAT444中的一种映射方式&#xff0c;它将一组端口范围映射到一个公有I…

【D3.js in Action 3 精译_034】4.1 D3 中的坐标轴的创建(中一)

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一部分 D3.js 基础知识 第一章 D3.js 简介&#xff08;已完结&#xff09; 1.1 何为 D3.js&#xff1f;1.2 D3 生态系统——入门须知1.3 数据可视化最佳实践&#xff08;上&#xff09;1.3 数据可…

MPA-SVM多变量回归预测|海洋捕食者优化算法-支持向量机|Matalb

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、算法介绍&#xff1a; 四、完整程序下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matlab平台编译&am…

Node.js概述

1. Node.js简介 Node.js是一个基于Chrome V8引擎的JavaScript运行环境。 地址&#xff1a;Node.js 中文网 1.1 Node.js中的JavaScript运行环境 &#xff08;1&#xff09;浏览器是JavaScript的前端运行环境 &#xff08;2&#xff09;Node.js是JavaScript的后端运行环境 …

2.使用 Label Studio 标注文本

使用 Label Studio 标注文本 文章目录 使用 Label Studio 标注文本前言Label Studio的简单使用1.创建项目2.添加本地存储3.选择标注模板4.添加数据5.标注6.添加关系 总结 前言 Label Studio是一个开源的功能强大的标注平台&#xff0c;可以标注视频&#xff0c;图片&#xff0…

Ubuntu终端配置

选择shell shell有很多&#xff0c;默认的是bash&#xff0c;一般就够用里&#xff0c;想要花里胡哨点就用zsh&#xff0c;还有最近比较火的fish 如果在刚开始安装完Ubuntu没有改shell&#xff0c;后面就不要改了。 安装的软件会设置环境变量&#xff0c;这些环境变量都是写入…