• leetcode树相关


    144前序遍历

    思路:(循环前入栈、先右节点入栈)

    • 建栈,入栈,循环,只要栈不为空
      • 出栈,把值加入res。
      • 如果右不为空,入栈。左一样。
    List<Integer> res = new ArrayList<>();
    if (root == null) {
        return res;
    }
    
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
        TreeNode curNode = stack.pop();
        res.add(curNode.val);
        // 下面用于非递归的反转二叉树
    //    TreeNode tempNode = node.left;
    //    node.left = node.right;
    //    node.right = tempNode;
    
        if (curNode.right != null) {
            stack.push(curNode.right);
        }
        if (curNode.left != null) {
            stack.push(curNode.left);
        }
    }
    return res;
    

    94中序遍历(98验证二叉搜索树、230二叉搜索树中第K小的元素)

    思路:

    • 建栈、cur指针,不入栈循环,只要cur和栈不为空
      • 只要cur不为空,循环让左子节点入栈,cur做相应移动
      • 出栈,把值加入res。
      • cur移动到右节点
    // 设置计数器(二叉搜索树中第K小的元素)
    // int cnt = 0;
    
    List<Integer> res = new ArrayList<>();
    
    if (root == null) {
        return res;
    }
    
    Stack<TreeNode> stack = new Stack<>();
    TreeNode cur = root;
    while (cur != null || !stack.isEmpty()) {
    
        // 先把左子节点都入栈
        /** 注意是cur != null,而不是cur.left != null */
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
    
        cur = stack.pop();
        // (二叉搜索树中第K小的元素)
    //      cnt++;
    //      if (cnt == k) return cur.val;
    
        // (验证二叉搜索树)
    //      if (pre != null && cur.val <= pre.val) return false;
    //      pre = cur;
        res.add(cur.val);
        cur = cur.right;
    }
    return res;
    

    145后序遍历

    思路:

    • 建栈、cur和pre指针
    • pop依然在中间,但add前要判断是否还有右节点或者之前就是右节点,否则把cur放回去,指向它的右节点。add后pre成为cur,cur变为null
    Stack<TreeNode> stack = new Stack<>();
    TreeNode pre = null;
    TreeNode cur = root;
    
    while (cur != null || !stack.isEmpty()) {
        while (cur != null) {
            stack.push(cur);
            cur = cur.left;
        }
    
        cur = stack.pop();
        if (cur.right == null || pre == cur.right) {
            res.add(cur.val);
            pre = cur;
            cur = null;
        } else {
            stack.push(cur);
            cur = cur.right;
        }
    }
    

    102/107层次遍历(104二叉树最大深度、103

    二叉树的锯齿形层次遍历)

    思路:

    • 新建queue,入列
    • 循环,只要q不为空
      • 新建level链表,记录本层元素的个数
      • 遍历此层
        • 出列,加入res。
        • 如果左节点不为空,入列。右节点一样。
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    
    while (!queue.isEmpty()) {
        // 下面用于 maxDepth
    //      res++;
    
    List<Integer> level = new ArrayList<>();
    // 注意,由于循环中对queue进行修改,其size不断变化,所以这个值不能直接放到循环条件中
    int length = queue.size();
    
    // 下面用于 zigzagLevelOrder
    //  boolean flag = result.size() % 2 == 0;
    
    for (int i = 0; i < length; i++) { // 遍历一层的node
        TreeNode node = queue.poll();
        level.add(node.val);
    
        // 下面用于 zigzagLevelOrder
    //      if (flag) level.add(node.val);
    //      else level.add(0, node.val);
    
        if (node.left != null) queue.offer(node.left);
        if (node.right != null) queue.offer(node.right);
    }
    // levelOrderBottom就 add(0, level)
    // 不断往0插入数据,旧数据就被挤到后面了
    result.add(level);
    

    105从前序与中序遍历序列构造二叉树

    思路:

    • 新建preStart, preEnd, inStart, inEnd四个变量
    • 调用递归函数
      • 当“前序”或者“中序”中其中一个结束,就返回null
      • 取出pre中的preStart元素,新建节点,然后在中序数组中找出该节点的index。根据这个index来划分左右子树对应“前序”和“中序”的边界
    // construct函数
    if (preStart > preEnd || inStart > inEnd) {
        return null;
    }
    
    int val = preorder[preStart];
    TreeNode p = new TreeNode(val);
    
    int k = 0;
    for (int i = 0; i < inorder.length; i++) {
        if (val == inorder[i]) {
            k = i;
            break;
        }
    }
    
    // 注意要减去inStart
    p.left = construct(preorder, preStart + 1, preStart + (k - inStart),
            inorder, inStart, k - 1);
    p.right = construct(preorder, preStart + (k - inStart) + 1, preEnd,
            inorder, k + 1, inEnd);
    
    return p;
    

    114二叉树展开为链表

    	1
       / 
      2   5
     /    
    3   4   6
    
    1
     
      2
       
        3
         
          4
           
            5
             
              6
    

    只能说,从上面的观察结果来看,可以先处理右节点,再到左节点的顺序。

    private TreeNode preNode = null;
    
    public void flatten(TreeNode root) {
       if (root == null) {
            return;
        }
        flatten(root.right);
        flatten(root.left);
        root.right = preNode;
        root.left = null;
        preNode = root;
    }
    

    124二叉树中的最大路径和

    思路:递归

    • 对左右节点递归调用函数,当节点为null时,返回0。如果返回的结果比0还小,可以不选该节点,所以以left为例,赋值为返回值及0中的最大值。
    • 返回左右节点值后,判断res是否需要更新,比较值是左右即当前节点值的和。
    • 最后只能返回一条路近的值,即从左到当前节点还是从右到当前节点的和。

    235/236二叉树的最近公共祖先

    236思路:

    target是p和q的最近公共父节点,它有两种情况
    要么p和q都不是target,要么p或q为target
    第一种情况:p和q会分布在target的左右两边,所以左右返回的都不是null,返回当前即可
    第二种情况:左右其中一个返回null,一个非null,直接返回非null即可
    递归寻找,root绝对会等于null或者p、q中的一个

    if (root == null || root == p || root == q) return root;
    
    TreeNode left = lowestCommonAncestor1(root.left, p, q);
    // 下面优化,说明左节点是一个非p或q的公共节点
    // if (left != null && left != p && left != q) return left;
    TreeNode right = lowestCommonAncestor1(root.right, p, q);
    
    if (left != null && right != null) return root;
    
    return left == null ? right : left;
    

    235思路:

    如果当前节点的值大于两个参数节点,说明它们的公共父节点在左边,反之。只有当当前节点的值处于两个值之间,当前节点才是公共父节点。

    if (root.val > p.val && root.val > q.val) {
        return lowestCommonAncestor2(root.left, p, q);
    } else if (root.val < p.val && root.val < q.val) {
        return lowestCommonAncestor2(root.right, p, q);
    } else {
        return root;
    }
    
  • 相关阅读:
    二级评论
    AFN上传数组
    简单播放音频
    好久不见~~ iOS开发动画(Animation)总结
    iOS开发中的单元测试(一)
    在 Xcode 中进行自动化测试 (2/2)
    在 Xcode 中进行自动化测试 (1/2)
    iOS中Bitcode的介绍及配置
    大牛博客
    关于iOS Push Notification的响应问题
  • 原文地址:https://www.cnblogs.com/code2one/p/10100189.html
Copyright © 2020-2023  润新知