二叉树LeetCode刷题

news2025/1/2 0:13:47

二叉树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;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法竞赛(Python)-AI的思维模式(搜索)

文章目录 一 、深度优先搜索1 零钱搭配2“油漆桶”与连通性 二 、记忆化三、在游戏中制胜的AI1 永远的平局——井字棋2 一起来解谜——数独3 数字华容道 一 、深度优先搜索 深度优先搜索是最基本的搜索方法&#xff0c;在深度优先搜索的过程中&#xff0c;如果把所有的可行解看…

如果你的YOLO环境已经配置好了,如何打开项目文件

1.首先将【目标检测系统源码】下载完成之后&#xff0c;解压到某个路径下&#xff08;可以解压在D盘或者F盘都可&#xff09;。然后使用Pycharm打开这个项目文件。 2.使用 pip 命令安装所需的依赖&#xff0c;可以通过requirements.txt文件进行安装。请务必按照 requirements.t…

springboot第76集:线程,ThreadGroup

导出数据&#xff1a; 查询结果可以使用脚本或工具&#xff08;如 Python 的 Pandas 库&#xff09;将数据导出为 Excel 格式。例如&#xff0c;使用 Python&#xff1a; 当查询数组中有大量数据&#xff08;如一千多条&#xff09;时&#xff0c;可以使用 _mget&#xff08;多…

系统分析师17:系统安全分析与设计

1 内容概述 2 对称加密与非对称加密技术 在信息安全领域&#xff0c;对称加密和非对称加密是两种最常见的加密技术。它们各自有不同的特点和应用场景&#xff0c;下面将详细介绍这两种加密技术。 2.1 对称加密 2.1.1 概念 对称加密是指使用相同的密钥&#xff08;也称为密钥…

opencv学习:风格迁移对图像风格进行更改

介绍&#xff1a; 风格迁移是一种计算机视觉技术&#xff0c;它能够让一张图片看起来像是用另一种风格画出来的。想象一下&#xff0c;你有一张普通的照片&#xff0c;但你希望它看起来像是梵高的印象派画作&#xff0c;或者像是某个著名艺术家的作品&#xff0c;风格迁移就可以…

C语言 ——— oj题:搜索插入位置

目录 题目要求 代码实现 题目要求 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置 请必须使用时间复杂度为 O(long n) 的算法 示例 1: 输入: nums [1,3,5,6], t…

golang包管理

package 在工程化的Go语言开发项目中&#xff0c;Go语言的源码复用是建立在包&#xff08;package&#xff09;基础之上的。本文介绍了Go语言中如何定义包、如何导出包的内容及如何导入其他包。 包与依赖管理 本章学习目标 掌握包的定义和使用掌握init初始化函数的使用掌握…

一、el-table的滚动条加粗并解决遮挡内容问题

近期接到产品提的需求&#xff0c;反馈用户说table里面的滚动条过小&#xff0c;不方便拖动&#xff0c;希望加粗&#xff0c;然后我就研究了下如何加粗&#xff0c;发现加粗后会导致遮挡内容的问题&#xff0c;并予以解决。以下是实现和解决的方法和步骤。 先看看官网的滚动条…

[翻译]MOSIP 101

目录 Architecture Principles of MOSIP &#xff08;MOSIP架构原则&#xff09; MOSIP Functional Architecture&#xff08;MOSIP功能架构&#xff09; MOSIP Features&#xff08;MOSIP特点&#xff09; MOSIP Modules&#xff08;MOSIP模块&#xff09; MOSIP Logical…

manjaro kde 24 应该如何设置才能上网(2024-10-13亲测)

要在 Manjaro KDE 24 上设置网络连接&#xff0c;可以按照以下步骤进行设置&#xff0c;确保你能够连接到互联网&#xff1a; 是的&#xff0c;你可以尝试使用一个简单的自动修复脚本来解决 Manjaro KDE 中的网络连接问题。这个脚本将检查网络服务、重新启动 NetworkManager、…

R语言统计分析——相关图

参考资料&#xff1a;R语言实战【第2版】 相关系数矩阵是多元统计分析的一个基本方面。哪些被考察的变量与其他变量相关性很强&#xff0c;而哪些并不强&#xff1f;随着变量数的增加&#xff0c;这类问题将变得很难回答。相关图作为一种相对现代的方法&#xff0c;可以通过相关…

Node.js 中的 WebSocket 底层实现

WebSockets 是一种网络通信协议&#xff0c;可实现双向客户端-服务器通信。 WebSockets 通常用于需要即时更新的应用程序&#xff0c;使用 HTTP 之上的持久双工通道来支持实时交互&#xff0c;而无需持续进行连接协商。服务器推送是 WebSockets 的众多常见用例之一。 本文首先…

剖析DNS劫持攻击原理及其防御措施

DNS劫持可导致用户访问到虚假网站&#xff0c;还可能使攻击者获取用户的敏感信息或利用受感染的计算机进行其他恶意活动。了解清楚DNS劫持攻击的原理有助于我们提升安全意识&#xff0c;避免个人信息泄露及财产损失。 1. 基础概念 DNS劫持是一种网络攻击&#xff0c;通过修改域…

低代码开发技术:驱动MES系统创新与制造业数字化转型的融合之路

低代码开发与生产管理MES系统的融合&#xff0c;是当今制造业数字化转型的一个重要趋势。以下是对这一融合现象的详细分析&#xff1a; 一、低代码开发的概念与特点 低代码开发是一种通过图形化界面和预构建模块来简化应用程序开发过程的方法。它允许开发人员使用拖放组件和最…

MT1331-MT1340 码题集 (c 语言详解)

MT1341反比例函数 c 语言实现代码 #include <stdio.h>double f(double x) { return 1.0 / x; }double trapezoidal_integration(double a, double b, int n) {// computer step lengthdouble h (b - a) / n;// computer points valuedouble sum (f(a) f(b)) / 2.0;//…

linux的sed命令

学习链接 Linux文本处理器sed - B站视频 文章目录 学习链接基础介绍语法格式sed的处理过程sed的选项-n-e-f-r-i pattern的7种用法sed中的编辑命令详解p 打印d 删除a 行后追加i 行前追加r 行后追加指定文件内容w 行追加到其它文件中 替换操作s/pattern/strings/pattern/string/…

【AI论文精读4】RAG论文综述2(微软亚研院 2409)P2-问题定义

【AI论文解读】【AI知识点】【AI小项目】【AI战略思考】【AI大项目】【AI应用】 P1 二、问题定义 数据增强的大语言模型&#xff08;LLM&#xff09;应用可以采取多种形式&#xff0c;从常见的基于领域特定数据的问答机器人&#xff0c;到复杂数据管道中的语义处理操作&#x…

AI工具在论文选题方面可以提供的帮助

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 在论文写作中&#xff0c;选题是决定研究质量和成果的关键步骤。随着人工智能技术的快速发展&#xff0c;AI工具在论文选题方面的应用逐渐受到关注。通过智能算法和大数据分析&#xff…

selenium安装

一、安装selenium 1&#xff0c;安装selenium -- 命令&#xff1a; pip install selenium -- 网络不稳的请换源安装&#xff1a; pip install selenium -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com 二、安装chrome webdriver 1.查看谷歌浏览器版本 …

Excel:vba实现合并工作表(表头相同)

这个代码应该也适用于一些表头相同的工作表的汇总&#xff0c;只需要修改想要遍历的表&#xff0c;适用于处理大量表头相同的表的合并 这里的汇总合并表 total 是我事先创建的&#xff0c;我觉得比用vba代码创建要容易一下&#xff0c;如果不事先创建汇总表就用下面的代码&…