一、二叉树天然的递归结构
二叉树遍历
private void preOrder(TreeNode node) {
if (node == null) {
return;
}
System.out.print(node.val);
preOrder(node.left);
preOrder(node.right);
}
查找存不存在某个值
private boolean contain(TreeNode node, Key key) {
if (node == null) {
return false;
}
if (key == node.key) {
return true;
}
if (contain(node.left, key) || contain(node.right, key)) {
return true;
}
return false;
}
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
int leftMaxDeph = maxDepth(root.left);
int rightMaxDeph = maxDepth(root.right);
return Math.max(leftMaxDeph, rightMaxDeph) + 1;
}
}
相关问题,111
class Solution {
public int minDepth(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left == null && root.right == null) {
return 1;
}
int min = Integer.MAX_VALUE;
if (root.left != null) {
min = Math.min(minDepth(root.left), min);
}
if (root.right != null) {
min = Math.min(minDepth(root.right), min);
}
return min + 1;
}
}
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {
return null;
}
TreeNode left =invertTree(root.left);
TreeNode right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
}
}
相关问题,100,101,222,110
class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (q == null || p == null) {
return false;
}
if (p.val != q.val) {
return false;
}
return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
}
}
class Solution {
public boolean isSymmetric(TreeNode root) {
return isMirror(root, root);
}
private boolean isMirror(TreeNode p, TreeNode q) {
if (p == null && q == null) {
return true;
}
if (p == null || q == null) {
return false;
}
return p.val == q.val && isMirror(p.left, q.right) && isMirror(p.right, q.left);
}
}
class Solution {
public boolean isBalanced(TreeNode root) {
return depth(root) != -1;
}
private int depth(TreeNode root) {
//节点为空层数是0
if (root == null) {
return 0;
}
//递归求左边
int left = depth(root.left);
//发现不是平衡,提前截断
if (left == -1) {
return -1;
}
//递归求右边
int right = depth(root.right);
// 发现不是平衡,提前截断
if (right == -1) {
return -1;
}
//比较深度,如果大于1说明不是平衡则返回-1
return Math.abs(left - right) < 2 ? Math.max(left, right) + 1 : -1;
}
}
二、注意递归的终止条件
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。
说明: 叶子节点是指没有子节点的节点。
示例:
给定如下二叉树,以及目标和 sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ \
7 2 1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
//注意题目要求必须是叶子节点
if (root.left == null && root.right == null) {
return root.val == sum;
}
if (hasPathSum(root.left, sum - root.val)) {
return true;
}
if (hasPathSum(root.right, sum - root.val)) {
return true;
}
return false;
}
}
相关问题,404
class Solution {
int sum = 0;
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0;
}
if (root.left != null && root.left.left == null && root.left.right == null) {
sum += root.left.val;
}
sumOfLeftLeaves(root.left);
sumOfLeftLeaves(root.right);
return sum;
}
}
给定一个二叉树,返回所有从根节点到叶子节点的路径。
输入:
1
/ \
2 3
\
5
输出: ["1->2->5", "1->3"]
解释: 所有根节点到叶子节点的路径为: 1->2->5, 1->3
class Solution {
public List<String> binaryTreePaths(TreeNode root) {
List<String> res = new ArrayList<>();
if (root == null) {
return res;
}
if (root.left == null && root.right == null) {
res.add(root.val+"");
return res;
}
List<String> leftS = binaryTreePaths(root.left);
for (int i = 0; i < leftS.size(); i++) {
res.add(root.val + "->" + leftS.get(i));
}
List<String> rightS = binaryTreePaths(root.right);
for (int i = 0; i < rightS.size(); i++) {
res.add(root.val + "->" + rightS.get(i));
}
return res;
}
}
相关问题,113,129
class Solution {
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> res = new ArrayList<>();
dfs(root,sum,res,new Stack<Integer>());
return res;
}
private void dfs(TreeNode root, int sum,List<List<Integer>> res,Stack<Integer> temp){
if(root==null){
return;
}
temp.add(root.val);
if(root.left==null&&root.right==null&&sum-root.val==0){
res.add(new ArrayList<>(temp));
}
dfs(root.left,sum-root.val,res,temp);
dfs(root.right,sum-root.val,res,temp);
temp.pop();
}
}
class Solution {
public int sumNumbers(TreeNode root) {
if(root==null){
return 0;
}
return dfs(root,0);
}
private int dfs(TreeNode root,int sum){
if(root==null){
return 0;
}
sum*=10;
sum+=root.val;
if(root.left==null&&root.right==null){
return sum;
}
return dfs(root.left,sum)+dfs(root.right,sum);
}
}
给定一个二叉树,它的每个结点都存放着一个整数值。
找出路径和等于给定数值的路径总数。
路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
二叉树不超过1000个节点,且节点数值范围是 [-1000000,1000000] 的整数。
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
返回 3。和等于 8 的路径有:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
class Solution {
public int pathSum(TreeNode root, int sum) {
if (root == null) {
return 0;
}
int res = findPath(root, sum);
res += pathSum(root.left, sum);
res += pathSum(root.right, sum);
return res;
}
private int findPath(TreeNode node, int num) {
if (node == null) {
return 0;
}
int res = 0;
if (node.val == num) {
res += 1;
}
res += findPath(node.left, num - node.val);
res += findPath(node.right, num - node.val);
return res;
}
}
三、二分搜索树中的问题
二分搜索树中的基本操作
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
思路:
1.从根节点开始遍历树
2.如果节点 p和节点 q 都在右子树上,那么以右孩子为根节点继续 1 的操作
3.如果节点 p 和节点 q 都在左子树上,那么以左孩子为根节点继续 1 的操作
4.如果条件 2 和条件 3 都不成立,这就意味着我们已经找到节 p 和节点 q 的 LCA 了
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
//如果p和q都小于父级
if (p.val < root.val && q.val < root.val) {
return lowestCommonAncestor(root.left, p, q);
}
//如果p和q都大于父级
if (p.val > root.val && q.val > root.val) {
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}
相关问题,98,450,108,230,236
class Solution {
//用的中序遍历,中序遍历值就是个升序数组
double last = -Double.MAX_VALUE;
public boolean isValidBST(TreeNode root) {
if(root==null){
return true;
}
//将左子节点先与根节点比较,再用根节点与右子节点比较
if(isValidBST(root.left)){
if(last<root.val){
last=root.val;
return isValidBST(root.right);
}
}
return false;
}
}
class Solution {
//这个题目根据数据结构书上的方法来
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null){
return null;
}
//到root的左子树中去删除节点,然后让root.left指向左子树删除节点后的根节点:
if(key<root.val){
root.left = deleteNode(root.left,key);
return root;
}
//到root的右子树中去删除节点,然后让root.right指向右子树删除节点后的根节点:
if(key>root.val){
root.right =deleteNode(root.right,key);
return root;
}
//key = root.val此时当前节点即为要删除的节点,此时,还要分三种情况:
//1、如果左子树为空,用他的右子树代替
if(root.left==null){
TreeNode right=root.right;
root.right = null;
return right;
}
//2、如果右子树为空,用他的左子树代替
if(root.right==null){
TreeNode left=root.left;
root.left=null;
return left;
}
//3、root的左右子树都不为空的情况
//使用右子树的最小的节点,代替当前要被删除的节点,再在右子树中删除该最小节点即可。
// 找到右子树的最小节点
TreeNode successor = minmum(root.right);
// 使用该最小节点代替要删除的节点,即:
// 1. 该节点的右子树为root的右子树删除该最小节点
// 2. 该节点的左子树为原来节点的左子树
// 3. 断开原来节点的左右子树
successor.right = removeMin(root.right);
successor.left = root.left;
root.left = root.right = null;
return successor;
}
//返回以node为跟的最小的节点
private TreeNode minmum(TreeNode treeNode){
if(treeNode.left==null){
return treeNode;
}
return minmum(treeNode.left);
}
//删除以node为跟的树中的最小节点,并返回删除后的树根节点
private TreeNode removeMin(TreeNode treeNode){
if(treeNode.left==null){
TreeNode rightNode=treeNode.right;
treeNode.right=null;
return rightNode;
}
treeNode.left=removeMin(treeNode.left);
return treeNode;
}
}
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
//高度平衡二叉搜索树,二分查找
return BST(nums,0,nums.length-1);
}
private TreeNode BST(int[] nums,int low,int height){
if(low>height){
return null;
}
int mid=(low+height)/2;
TreeNode root = new TreeNode(nums[mid]);
root.left = BST(nums,low,mid-1);
root.right = BST(nums,mid+1,height);
return root;
}
}
class Solution {
//二叉搜索树(二叉查找树、二叉排序树、BST)的中序遍历就是其所有节点的val按照升序排列。
//这样根据中序遍历,每找到一个元素判断他是否是第k个元素即可。
private int val;
private int index=0;
public int kthSmallest(TreeNode root, int k) {
ldr(root,k);
return val;
}
private void ldr(TreeNode node,int k){
if(node==null){
return;
}
ldr(node.left,k);
if(++index==k){
val=node.val;
}
ldr(node.right,k);
}
}
class Solution {
private TreeNode ans=null;
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
recurseTree(root, p, q);
return ans;
}
private boolean recurseTree(TreeNode currentNode, TreeNode p, TreeNode q) {
//如果到达分支的末尾,则返回false
if (currentNode == null) {
return false;
}
//左递归。如果left递归返回true,则设置left = 1否则为0
int left=recurseTree(currentNode.left,p,q)?1:0;
//右递归
int right=recurseTree(currentNode.right,p,q)?1:0;
//如果当前节点是p或q
int mid = (currentNode == p || currentNode == q) ? 1 : 0;
//如果左,右或中两个标志中的任意两个变为True
if (mid + left + right >= 2) {
ans = currentNode;
}
return (mid + left + right > 0);
}
}