二叉树经典题

 先根(根左右)

思路:

1. 栈中放入根 2. 遍历栈 先放入右节点 然后放入左姐递单

public List<Integer> preOrderTraversal(TreeNode root) {
        LinkedList<Integer> res = new LinkedList<>();
        if (root == null) return res;
        
        Stack<TreeNode> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            TreeNode node = stack.pop();
            res.add(node);
            //注意是根 左 右 所以先放入右节点到栈中
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
        return res;
    }

中根(左根右)

思路:

1. 将根节点入栈 2. 将所有左节点入栈 3. 每次出栈后 放入右节点

public List<Integer> inOrderTraversal(TreeNode root) {
        LinkedList<Integer> res = new LinkedList<>();
        if (root == null) return res;

        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            res.add(root.val);
            root = root.right;
        }
        return res;
    }

后根遍历(左右根)

思路:

1. 通过栈 找到最右侧节点 2. 遍历顺序是 根右左 3. 采用头插入 结果是左右根

public List<Integer> postorderTraversal(TreeNode root) {
        LinkedList<Integer> res = new LinkedList<>();
        Stack<TreeNode> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
            //因为左右根 所以头插入
                res.addFirst(root.val);
                stack.push(root);
                root = root.right;
            }
            root = stack.pop().left;
        }
        return res;
    }

层次遍历

思路: 通过队列 每次遍历一层

public List<List<Integer>> levelOrderTraversal(TreeNode root) {
        LinkedList<List<Integer>> res = new LinkedList<>();
        if (root == null) return res;

        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        int level = 0;
        while (!queue.isEmpty()) {
            res.add(new ArrayList<>());
            for (int i = 0; i < queue.size(); i++) {
                TreeNode node = queue.poll();
                res.get(level).add(node);

                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
            level++:
        }
        return res;
    }

根据先跟和中跟构建树

public TreeNode buildTree(int[] pre, int[] in) {
	if (pre == null || in == null || pre.length == 0 || in.length == 0) return null;
	if (pre.length != in.length) return null;

	TreeNode root = new TreeNode(pre[0]);
	for (int i = 0; i < pre.length; i++) {
		if (in[i] == pre[0]) {
			root.left = buildTree(Arrays.copyOfRange(pre, 1, i+1), Arrays.copyOfRange(in, 0,i));
			root.right = buildTree(Arrays.copyOfRange(pre, i+1, pre.length), Arrays.copyOfRange(in, i+1, in.length));
		}
	}
	return root;
}

求和为指定值的路径个数

注意:不强制要求是从根节点开始

class Solution {
    int res = 0;
    public int pathSum(TreeNode root, int sum) {
        if (root == null) return 0;
        //从根出发
        help(root, sum, root.val);
        //从左子树出发
        pathSum(root.left, sum);
        //从右子树出发
        pathSum(root.right, sum);
        return res;
    }
    private void help (TreeNode root, int target, int sum) {
        if (root == null) return;
        if (sum == target) {
            res++;
        }
        if (root.left != null) {
            help(root.left, target, sum + root.left.val);
        }
        if (root.right != null) {
            help(root.right, target, sum+root.right.val);
        }
    }
}

求和为指定值的路径集合

注意:要求从根节点到叶子节点

思路:回溯三步骤

1. 确定递归结束条件,当前节点为null

2. 确定处理逻辑。 如果是叶子节点并且余数=0 则放入结果集合中 否则递归左右子树 进行回溯

3. 确定方法参数。参数一:当前节点 参数二:余数

class Solution {
    List<List<Integer>> res = new LinkedList();
    Stack<Integer> path = new Stack();
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
        help(root, sum);
        return res;
    }
    private void help(TreeNode root, int sum) {
        if (root == null) return;
        sum -= root.val;
        path.push(root.val);
        //和满足条件 并且 是叶子结点
        if (sum == 0 && root.left == null && root.right == null) {
            res.add(new LinkedList(path));
        }
        //递归左右子树
        help(root.left, sum);
        help(root.right, sum);
        //回溯
        path.pop();
    }
}

求是否存在从根到叶子节点路径和等于指定的值

public boolean hasPathSum(TreeNode root, int sum) {
        if (root == null) return false;

        Stack<TreeNode> nodeStack = new Stack();
        Stack<Integer> sumStack = new Stack();
        nodeStack.push(root);
        sumStack.push(sum);
        while (!nodeStack.isEmpty()) {
            TreeNode node = nodeStack.pop();
            int tmp = sumStack.pop();
            if (node.left == null && node.right == null && (tmp-node.val) == 0) {
                return true;
            }
            if (node.left != null) {
                nodeStack.push(node.left);
                sumStack.push(tmp-node.val);
            }
            if (node.right != null) {
                nodeStack.push(node.right);
                sumStack.push(tmp-node.val);
            }
        }
        return false;
    }

二叉搜索树返回指定节点的后继节点

public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
        if (root == null) return null;

        if (p.val >= root.val) {
            return inorderSuccessor(root.right, p);
        }else {
            TreeNode node = inorderSuccessor(root.left, p);
            //不等于null 则返回右子树的最左节点
            //等于null 则说明当前节点的左节点为null 返回当前节点
            return node == null ? root : node;
        }
    }

中序遍历的下一个节点

private static Integer getNext(TreeNode tree) {
        // TODO Auto-generated method stub
        // 如果有右孩子,则下一个节点是右孩子中最左子节点
        TreeNode temp;
        if (tree.right != null) {
            temp = tree.right;
            while (temp.left != null) {
                temp = temp.left;
            }
            return temp.val;
        }
        // 节点是其父节点的左子节点,则下一个节点就是父节点(节点没有右孩子)
        if (tree.father != null && tree.father.left == tree) {
            return tree.father.val;
        }
        // 如果节点是父节点的右子节点(节点没有右孩子),下一个节点:父节点是其父节点的左孩子
        if (tree.father != null && tree.father.right == tree) {
            temp = tree.father;
            while (temp != null) {
                if (temp.father.left == temp) {
                    return temp.father.val;
                }
                temp = temp.father;
            }
            // 最后没找到的话 就说明这是最后一个,不存在他的下一个了
        }
        return null;
    }

合法二叉搜索树

public boolean isValidBST(TreeNode root) {
        if (root == null) return true;

        Stack<TreeNode> stack = new Stack();
        double tmp = -Double.MAX_VALUE;
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root. left;
            }
            root = stack.pop();
            if (root.val <= tmp) {
                return false;
            }
            tmp = root.val;
            root = root.right;
        }
        return true;
    }

树中每行的最大值

public List<Integer> largestValues(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            int max = Integer.MIN_VALUE;
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                max = Math.max(max, node.val);
                if (node.left != null) {
                    queue.add(node.left);
                }
                if (node.right != null) {
                    queue.add(node.right);
                }
            }
            res.add(max);
        }
        return res;
    }

最近公共祖先

public TreeNode lowest(TreeNode root, TreeNode p, TreeNode q) {
	if (root == null || root == p || root == q) return root;

	TreeNode left = lowest(root.left, p, q);
	TreeNode right = lowest(root.right, p, q);
	if (left != null && right != null) return root;
	return left == null ? right : left;
}

二叉搜索树的第k小的元素

    public int kthSmallest(TreeNode root, int k) {
        Stack<TreeNode> stack = new Stack();
        while (true) {
            while(root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            if (--k  == 0) return root.val;
            root = root.right;
        }
    }

每层节点所构成的链表集合

    ArrayList<ListNode> res = new ArrayList();
    public ListNode[] listOfDepth(TreeNode tree) {
        if (tree == null) return new ListNode[0];

        help(tree);
        return res.toArray(ListNode[]::new);
    }
    private void help(TreeNode root) {
        if (root == null) return;
        Queue<TreeNode> queue = new LinkedList();
        queue.add(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            ListNode node = new ListNode(-1);
            ListNode cur = node;
            for (int i = 0; i < size; i++) {
                TreeNode tmp = queue.poll();
                cur.next = new ListNode(tmp.val);
                cur = cur.next;
                if (tmp.left != null) {
                    queue.add(tmp.left);
                }
                if (tmp.right != null) {
                    queue.add(tmp.right);
                }
            }
            if (node.next != null) {
                res.add(node.next);
            }
        }
    }

判断是否是平衡二叉树

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) return true;
        return help(root) != -1;
    }
    private int help(TreeNode root) {
        if (root == null) return 0;
        //判断左子树是否平衡
        int left = help(root.left);
        //不平衡则提前结束(剪枝)
        if (left == -1) return -1;
        int right = help(root.right);
        if (right == -1) return -1;
        //左右子树各自平衡, 判断左右子树是否平衡, 不平衡返回-1, 平衡返回高度
        return Math.abs(left-right) < 2 ? Math.max(left,right)+1 : -1;
    }
    //时间复杂度为 O(n) 每个节点遍历1遍
}

二叉搜索树的最近公共祖先

public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(root != null) {
            if (p.val < root.val && q.val < root.val) {
                root = root.left;
            }else if (p.val > root.val && q.val > root.val) {
                root = root.right;
            }else {
                break;
            }
        }
        return root;
    }

二叉搜索树的第k大节点

    int res = 0, k = 0; 
    public int kthLargest(TreeNode root, int k) {
        this.k = k;
        help(root);
        return res;
    }
    private void help(TreeNode root) {
        if (root == null) return;
        //找中序遍历的倒序 (右 根 左) 第k个节点
        help(root.right);
        if (--k == 0) {
            res = root.val;
            return;
        }
        help(root.left);
    }

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值