当前位置: 首页 > news >正文

二叉树的总结

目录

二叉树的遍历

递归遍历

前序

中序

后序

迭代遍历

前序

中序

后序

统一迭代遍历

层序遍历

求二叉树的属性

判断二叉树是否对称:101. 对称二叉树 - 力扣(LeetCode)

求二叉树最大深度:104. 二叉树的最大深度 - 力扣(LeetCode)

求二叉树最小深度:111. 二叉树的最小深度 - 力扣(LeetCode)

求有多少个节点:222. 完全二叉树的节点个数 - 力扣(LeetCode)

判断二叉树是否平衡:110. 平衡二叉树 - 力扣(LeetCode)

找二叉树的所有路径:257. 二叉树的所有路径 - 力扣(LeetCode)

 求二叉树路径总和:112. 路径总和 - 力扣(LeetCode)

求二叉树所有左叶子的和:404. 左叶子之和 - 力扣(LeetCode)

求二叉树左下角的值:513. 找树左下角的值 - 力扣(LeetCode)

二叉树的修改和构造

翻转二叉树:226. 翻转二叉树 - 力扣(LeetCode)

构造二叉树

从中序与后序遍历序列构造二叉树:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)

从前序和中序遍历构造二叉树:105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

构造最大二叉树:654. 最大二叉树 - 力扣(LeetCode)

合并二叉树:617. 合并二叉树 - 力扣(LeetCode)

求二叉搜索树的属性

二叉搜索树中的搜索:700. 二叉搜索树中的搜索 - 力扣(LeetCode)

验证二叉搜索树:98. 验证二叉搜索树 - 力扣(LeetCode)

求二叉搜索树的最小绝对差:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

求二叉搜索树的众数:501. 二叉搜索树中的众数 - 力扣(LeetCode)

把二叉搜索树转成累加树:538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)

二叉树的公共祖先问题

二叉树的公共祖先:236. 二叉树的最近公共祖先 - 力扣(LeetCode)

二叉搜索树的公共祖先:235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

二叉搜索树的修改与改造

二叉搜索树中的插入操作:701. 二叉搜索树中的插入操作 - 力扣(LeetCode)

二叉搜索树中的删除操作:450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

修剪二叉搜索树:669. 修剪二叉搜索树 - 力扣(LeetCode)

构造二叉搜索树:108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)


二叉树的遍历

递归遍历

前序

class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list=new ArrayList<>();if(root==null)return list;list.add(root.val);list.addAll(preorderTraversal(root.left));list.addAll(preorderTraversal(root.right));return list;}
}

中序

 class Solution {public List<Integer> inorderTraversal(TreeNode root) {//递归法List<Integer> list=new ArrayList<>();if(root==null)return list;list.addAll(inorderTraversal(root.left));list.add(root.val);list.addAll(inorderTraversal(root.right));return list;}
}

后序

 class Solution {public List<Integer> postorderTraversal(TreeNode root) {//递归法List<Integer> list=new ArrayList<>();if(root==null)return list;list.addAll(postorderTraversal(root.left));list.addAll(postorderTraversal(root.right));list.add(root.val);return list;}
}

迭代遍历

前序

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

中序

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

后序

 class Solution {public List<Integer> postorderTraversal(TreeNode root) {List<Integer> list = new ArrayList<>();if (root == null)return list;Stack<TreeNode> st = new Stack<>();st.push(root);while(!st.isEmpty()){TreeNode node=st.pop();list.add(node.val);if(node.left!=null){st.push(node.left);}if(node.right!=null){st.push(node.right);}}Collections.reverse(list);return list;}
}

统一迭代遍历

上述前中后序的迭代遍历写法不一,这里给出统一的写法:

当栈不为空时,首先找到队列的头节点,如果该节点不为空,将该节点弹出(避免重复操作),再将右左中节点依次(中序就是右中左,后序就是中右左)添加到栈中,因为中节点被访问过所以在其后加入空节点作为标记,只有之后遇到这个空节点时,才能将下一个节点放进结果集。

 class Solution {public List<Integer> preorderTraversal(TreeNode root) {List<Integer> list=new ArrayList<>();if(root==null)return list;Stack<TreeNode> st=new Stack<>();st.push(root);while(!st.isEmpty()){TreeNode node=st.peek();if(node!=null){st.pop();if(node.right!=null)st.push(node.right);if(node.left!=null)st.push(node.left);st.push(node);st.push(null);}else{st.pop();node=st.pop();list.add(node.val);}}return list;}
}

前中后序在统一迭代写法的区别就在这几行: 

if(node.right!=null)st.push(node.right);
if(node.left!=null)st.push(node.left);
st.push(node);
st.push(null);

前序遍历的写法就是上述这样,按右左中的顺序依次放入栈,中序遍历的写法就是按右中左的顺序,后序遍历就是按中右左的顺序。 

层序遍历

不再是深度优先遍历,而是广度优先。

class Solution {public List<List<Integer>> reslist=new ArrayList<List<Integer>>();public List<List<Integer>> levelOrder(TreeNode root) {check(root);return reslist;}public void check(TreeNode node){if(node==null)return;Queue<TreeNode> q=new LinkedList<>();q.offer(node);while(!q.isEmpty()){List<Integer> list=new ArrayList<>();int len=q.size();while(len>0){TreeNode tmp=q.poll();list.add(tmp.val);if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);len--;}reslist.add(list);}}
}

求二叉树的属性

判断二叉树是否对称:101. 对称二叉树 - 力扣(LeetCode)

递归:比较根节点的左子树和右子树是不是相互翻转的

class Solution {public boolean isSymmetric(TreeNode root) {return compare(root.left,root.right);}public boolean compare(TreeNode left,TreeNode right){if(left==null&&right==null)return true;else if(left==null&&right!=null)return false;else if(left!=null&&right==null)return false;else if(left.val!=right.val)return false;boolean compareOutside=compare(left.left,right.right);boolean compareInside=compare(left.right,right.left);return compareOutside&compareInside;}}

迭代: 使用队列或栈将两个节点顺序放入容器中进行比较

 class Solution {public boolean isSymmetric(TreeNode root){return check(root);}public boolean check(TreeNode node){Queue<TreeNode> q=new LinkedList<>();q.offer(node.left);q.offer(node.right);while(!q.isEmpty()){TreeNode left=q.poll();TreeNode right=q.poll();if(left==null&&right==null)continue;else if(left==null||right==null||left.val!=right.val)return false;q.offer(left.left);q.offer(right.right);q.offer(left.right);q.offer(right.left);}return true;}
}

求二叉树最大深度:104. 二叉树的最大深度 - 力扣(LeetCode)

递归:求根节点的最大高度就是最大深度

class Solution {public int maxDepth(TreeNode root) {if(root==null)return 0;int leftDepth=maxDepth(root.left);int rightDepth=maxDepth(root.right);return Math.max(leftDepth,rightDepth)+1;}
}

迭代:层序遍历

class Solution {public int maxDepth(TreeNode root) {int depth=0;if(root==null)return 0;Queue<TreeNode> q=new LinkedList<>();q.offer(root);while(!q.isEmpty()){int len=q.size();while(len>0){TreeNode tmp=q.poll();if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);len--;}depth++;}return depth;}
}

求二叉树最小深度:111. 二叉树的最小深度 - 力扣(LeetCode)

递归:求根节点的最小高度就是最小深度

class Solution {public int minDepth(TreeNode root) {if(root==null)return 0;int leftDepth=minDepth(root.left);int rightDepth=minDepth(root.right);if(leftDepth==0)return rightDepth+1;if(rightDepth==0)return leftDepth+1;return Math.min(leftDepth,rightDepth)+1;}
}

迭代:层序遍历

 class Solution {public int minDepth(TreeNode root) {int depth=0;if(root==null)return 0;Queue<TreeNode> q=new LinkedList<>();q.offer(root);while(!q.isEmpty()){int len=q.size();while(len>0){TreeNode tmp=q.poll();if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);if(tmp.left==null&&tmp.right==null)return depth+1;len--;}depth++;}return depth;}
}

求有多少个节点:222. 完全二叉树的节点个数 - 力扣(LeetCode)

递归:

class Solution {public int countNodes(TreeNode root) {if(root==null)return 0;int left=countNodes(root.left);int right=countNodes(root.right);int count=0;if(root!=null)count++;return left+right+count;}
}

迭代:

class Solution {public int countNodes(TreeNode root) {if(root==null)return 0;Queue<TreeNode> q=new LinkedList<>();List<Integer> list=new ArrayList<>();if(root!=null)q.offer(root);while(!q.isEmpty()){int len=q.size();while(len>0){TreeNode tmp=q.poll();if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);list.add(tmp.val);len--;}}return list.size();}
}

判断二叉树是否平衡:110. 平衡二叉树 - 力扣(LeetCode)

递归:递归过程判断高度差

class Solution {public boolean isBalanced(TreeNode root) {if(root==null)return true;if(Height(root)==-1)return false;return true;}public int Height(TreeNode node){if(node==null)return 0;int leftHeight=Height(node.left);if(leftHeight==-1)return -1;int rightHeight=Height(node.right);if(rightHeight==-1)return -1;if(Math.abs(leftHeight-rightHeight)>1)return -1;return Math.max(leftHeight,rightHeight)+1;}}
}

迭代:效率很低,不推荐

 class Solution {public boolean isBalanced(TreeNode root){if(root==null)return true;Stack<TreeNode> st=new Stack<>();if(root!=null)st.push(root);while(!st.isEmpty()){TreeNode node=st.pop();if(node!=null){st.push(node);st.push(null);if(node.right!=null)st.push(node.right);if(node.left!=null)st.push(node.left);}else{node=st.pop();if(Math.abs(Height(node.left)-Height(node.right))>1)return false;}}return true;}public int Height(TreeNode node){if(node==null)return 0;Queue<TreeNode> q=new LinkedList<>();q.offer(node);int res=0;while(!q.isEmpty()){int len=q.size();while(len>0){TreeNode tmp=q.poll();if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);len--;}res++;}return res;}
}

找二叉树的所有路径:257. 二叉树的所有路径 - 力扣(LeetCode)

递归:涉及回溯处理根节点到叶子的所有路径

class Solution {public List<String> binaryTreePaths(TreeNode root){List<String> list=new ArrayList<>();if(root==null)return null;List<Integer> path=new ArrayList<>();findPaths(root,path,list);return list;}public void findPaths(TreeNode node,List<Integer> path,List<String> res){path.add(node.val);if(node.left==null&&node.right==null){//叶子节点StringBuffer sb=new StringBuffer();for(int i=0;i<path.size()-1;i++){sb.append(path.get(i)+"->");}sb.append(path.get(path.size()-1));res.add(sb.toString());return;}if(node.left!=null){findPaths(node.left,path,res);path.remove(path.size()-1);//回溯}if(node.right!=null){findPaths(node.right,path,res);path.remove(path.size()-1);//回溯}}
}

迭代法:把节点和路径同时放入栈中

class Solution {public List<String> binaryTreePaths(TreeNode root) {List<String> list=new ArrayList<>();Stack<Object> st=new Stack<>();if(root!=null){//节点和路径同时入栈st.push(root);st.push(root.val+"");}while(!st.isEmpty()){//节点和路径同时出栈String path=(String)st.pop();TreeNode node=(TreeNode)st.pop();//找到叶子节点if(node.left==null&&node.right==null){list.add(path);}//右子节点不为空if(node.right!=null){st.push(node.right);st.push(path+"->"+node.right.val);}//左子节点不为空if(node.left!=null){st.push(node.left);st.push(path+"->"+node.left.val);}}return list;}
}

 求二叉树路径总和:112. 路径总和 - 力扣(LeetCode)

递归:和上述找二叉树的所有路径思路一样,只需稍作修改即可

class Solution {public boolean hasPathSum(TreeNode root, int targetSum) {if(root==null)return false;return findPaths(root,0,targetSum);}public boolean findPaths(TreeNode node,int pathSum,int targetSum){pathSum+=node.val;if(node.left==null&&node.right==null&&pathSum==targetSum)return true;boolean left=false;boolean right=false;if(node.left!=null){left=findPaths(node.left,pathSum,targetSum);}if(node.right!=null){right=findPaths(node.right,pathSum,targetSum);}return left||right;}
}

迭代: 

class Solution {public boolean hasPathSum(TreeNode root, int targetSum) {if(root==null)return false;Stack<Object> st=new Stack<>();st.push(root);st.push(root.val);while(!st.isEmpty()){int pathSum=(Integer)st.pop();System.out.println(pathSum);TreeNode tmp=(TreeNode)st.pop();if(tmp.left!=null){st.push(tmp.left);st.push(pathSum+tmp.left.val);}if(tmp.right!=null){st.push(tmp.right);st.push(pathSum+tmp.right.val);}if(tmp.left==null&&tmp.right==null&&pathSum==targetSum)return true;}return false;}
}

求二叉树所有左叶子的和:404. 左叶子之和 - 力扣(LeetCode)

递归:后序,必须有三个约束条件才能判断是否是左叶子

class Solution {public int sumOfLeftLeaves(TreeNode root) {if(root==null)return 0;int left=sumOfLeftLeaves(root.left);int right=sumOfLeftLeaves(root.right);int mid=0;if(root.left!=null&&root.left.left==null&&root.left.right==null){mid=root.left.val;}return mid+left+right;}
}

迭代:层序遍历法

class Solution {public int sumOfLeftLeaves(TreeNode root) {if(root==null)return 0;Queue<TreeNode> q=new LinkedList<>();int res=0;if(root!=null)q.offer(root);while(!q.isEmpty()){int len=q.size();while(len>0){TreeNode tmp=q.poll();if(tmp.left!=null&&tmp.left.left==null&&tmp.left.right==null)res+=tmp.left.val;if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);len--;}}return res;}
}

求二叉树左下角的值:513. 找树左下角的值 - 力扣(LeetCode)

递归:优先左孩子搜索,同时找深度最大的叶子节点

class Solution {int maxDepth = 0;int res = 0;public int findBottomLeftValue(TreeNode root) {//递归traversal(root,1);return res;}public void traversal(TreeNode node, int depth) {if (node.left == null && node.right == null) {if (depth > maxDepth) {maxDepth = depth;res=node.val;}return;}if(node.left!=null){depth++;traversal(node.left,depth);depth--;}if(node.right!=null){depth++;traversal(node.right,depth);depth--;}}
}

迭代:层序遍历找最后一行左边

class Solution {public int findBottomLeftValue(TreeNode root) {Deque<TreeNode> q=new LinkedList<>();List<List<Integer>> res=new ArrayList<List<Integer>>();q.offer(root);while(!q.isEmpty()){List<Integer> list=new ArrayList<>();int len=q.size();while(len>0){TreeNode tmp=q.poll();if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);list.add(tmp.val);len--;}res.add(list);}return res.get(res.size()-1).get(0);}
}

二叉树的修改和构造

翻转二叉树:226. 翻转二叉树 - 力扣(LeetCode)

递归:前序,交换左右孩子

class Solution {public TreeNode invertTree(TreeNode root) {if(root==null)return null;swapChildren(root);invertTree(root.left);invertTree(root.right);return root;}public void swapChildren(TreeNode node){TreeNode tmp=node.right;node.right=node.left;node.left=tmp;}} 

迭代:层序遍历

 class Solution {public TreeNode invertTree(TreeNode root){check(root);return root;}public void check(TreeNode node){if(node==null)return;Queue<TreeNode> q=new LinkedList<>();q.offer(node);while(!q.isEmpty()){int len=q.size();while(len>0){TreeNode tmp=q.poll();swapChildren(tmp);if(tmp.left!=null)q.offer(tmp.left);if(tmp.right!=null)q.offer(tmp.right);len--;}}}public void swapChildren(TreeNode node){TreeNode tmp=node.right;node.right=node.left;node.left=tmp;}} 

构造二叉树

重点在于找分割点,分左右区间构造。

从中序与后序遍历序列构造二叉树:106. 从中序与后序遍历序列构造二叉树 - 力扣(LeetCode)
class Solution {public TreeNode buildTree(int[] inorder, int[] postorder) {if(inorder.length==0||postorder.length==0)return null;return build(inorder,0,inorder.length,postorder,0,postorder.length);}//左闭右开public TreeNode build(int[] inorder,int instart,int inend,int[] postorder,int poststart,int postend){if(poststart==postend)return null;int rootval=postorder[postend-1];TreeNode root=new TreeNode(rootval);int index=0;for(index=instart;index<inend;index++){if(inorder[index]==rootval)break;}int leftinstart=instart;int leftinend=index;int rightinstart=index+1;int rightinend=inend;int leftpoststart=poststart;int leftpostend=poststart+index-instart;int rightpoststart=poststart+index-instart;int rightpostend=postend-1;root.left=build(inorder,leftinstart,leftinend,postorder,leftpoststart,leftpostend);root.right=build(inorder,rightinstart,rightinend,postorder,rightpoststart,rightpostend);return root;}
}
从前序和中序遍历构造二叉树:105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
class Solution {public TreeNode buildTree(int[] preorder, int[] inorder) {if(preorder.length==0||inorder.length==0)return null;return build(preorder,0,preorder.length,inorder,0,inorder.length);}//左闭右开public TreeNode build(int[] preorder,int prestart,int prend,int[] inorder,int instart,int inend){if(prestart==prend)return null;int rootval=preorder[prestart];TreeNode root=new TreeNode(rootval);int index=0;for(index=instart;index<inend;index++){if(inorder[index]==rootval)break;}int leftinstart=instart;int leftinend=index;int rightinstart=index+1;int rightinend=inend;int leftprestart=prestart+1;int leftprend=prestart+index-instart+1;int rightprestart=leftprend;int rightprend=prend;root.left=build(preorder,leftprestart,leftprend,inorder,leftinstart,leftinend);root.right=build(preorder,rightprestart,rightprend,inorder,rightinstart,rightinend);return root;}
}

构造最大二叉树:654. 最大二叉树 - 力扣(LeetCode)

依旧是找分割点,分割左右区间。

class Solution {public TreeNode constructMaximumBinaryTree(int[] nums) {if(nums.length==0)return null;return build(nums,0,nums.length);}public int findMaxIndex(int[] arr,int start,int end){int Max=arr[start];int index=start;for(int i=start+1;i<end;i++){if(arr[i]>Max){Max=arr[i];index=i;}}//System.out.println(Max);return index;}//左闭右开public TreeNode build(int[] arr,int start,int end){if(start==end)return null;int leftstart,leftend,rightstart,rightend;int index=findMaxIndex(arr,start,end);TreeNode root=new TreeNode(arr[index]);leftstart=start;leftend=index;rightstart=index+1;rightend=end;TreeNode left=build(arr,leftstart,leftend);TreeNode right=build(arr,rightstart,rightend);root.left=left;root.right=right;return root;}
}

合并二叉树:617. 合并二叉树 - 力扣(LeetCode)

递归:前序,同时操作两个树的节点,注意合并的规则

 class Solution {public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {if(root1==null&&root2==null)return null;if(root1==null)return root2;if(root2==null)return root1;int val=(root1==null?0:root1.val)+(root2==null?0:root2.val);TreeNode root=new TreeNode(val);root.left=mergeTrees(root1.left,root2.left);root.right=mergeTrees(root1.right,root2.right);return root;  }
}

迭代:使用队列,类似层序遍历

class Solution {public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {if(root1==null&&root2==null)return null;if(root1==null)return root2;if(root2==null)return root1;Deque<TreeNode> q=new LinkedList<>();q.push(root2);q.push(root1);while(!q.isEmpty()){TreeNode tmp1=q.pop();TreeNode tmp2=q.pop();tmp1.val+=tmp2.val;if(tmp1.left!=null&&tmp2.left!=null){q.push(tmp2.left);q.push(tmp1.left);}if(tmp1.right!=null&&tmp2.right!=null){q.push(tmp2.right);q.push(tmp1.right);}if(tmp1.left==null&&tmp2.left!=null)tmp1.left=tmp2.left;if(tmp1.right==null&&tmp2.right!=null)tmp1.right=tmp2.right;    }return root1;}
}

求二叉搜索树的属性

二叉搜索树中的搜索:700. 二叉搜索树中的搜索 - 力扣(LeetCode)

递归:

class Solution {public TreeNode searchBST(TreeNode root, int val) {if(root==null)return null;if(root.val==val)return root;if(root.val>val)return searchBST(root.left,val);return searchBST(root.right,val);}
}

迭代: 

class Solution {public TreeNode searchBST(TreeNode root, int val) {if(root==null||root.val==val)return root;Stack<TreeNode> st=new Stack<>();st.push(root);while(!st.isEmpty()){TreeNode node=st.pop();if(node.val>val){if(node.left!=null)st.push(node.left);else return null;}else if(node.val<val){if(node.right!=null)st.push(node.right);else return null;}else return node;}return null;}
}

验证二叉搜索树:98. 验证二叉搜索树 - 力扣(LeetCode)

递归:中序,相当于判断一个序列是不是递增的

class Solution {public boolean isValidBST(TreeNode root) {List<Integer> list=inorder(root);for(int i=0;i<list.size()-1;i++){if(list.get(i)>=list.get(i+1))return false;}return true;}public List<Integer> inorder(TreeNode node){List<Integer> list=new ArrayList<>();if(node==null)return list;list.addAll(inorder(node.left));list.add(node.val);list.addAll(inorder(node.right));return list;}}
}

 迭代:模拟中序,逻辑相同

class Solution {public boolean isValidBST(TreeNode root){Stack<TreeNode> st=new Stack<>();List<Integer> list=new ArrayList<>();if(root!=null)st.push(root);while(!st.isEmpty()){TreeNode node=st.pop();if(node!=null){if(node.right!=null)st.push(node.right);st.push(node);st.push(null);if(node.left!=null)st.push(node.left);}else{node=st.pop();list.add(node.val);}}for(int i=0;i<list.size()-1;i++){if(list.get(i)>=list.get(i+1))return false;}return true;}
}

求二叉搜索树的最小绝对差:530. 二叉搜索树的最小绝对差 - 力扣(LeetCode)

递归:中序,引入一个pre节点,保留前序节点

class Solution {int res=Integer.MAX_VALUE;TreeNode pre=null;public int getMinimumDifference(TreeNode root) {if(root==null)return 0;getMinimumDifference(root.left);if(pre!=null)res=Math.min(res,root.val-pre.val);pre=root;getMinimumDifference(root.right);return res;}
}

迭代:模拟中序,逻辑相同

class Solution {public int getMinimumDifference(TreeNode root) {int res=Integer.MAX_VALUE;TreeNode pre=null;Stack<TreeNode> st=new Stack<>();st.push(root);while(!st.isEmpty()){TreeNode node=st.pop();if(node!=null){if(node.right!=null)st.push(node.right);st.push(node);st.push(null);if(node.left!=null)st.push(node.left);}else{TreeNode tmp=st.pop();if(pre!=null)res=Math.min(res,tmp.val-pre.val);pre=tmp;}}return res;}
}

求二叉搜索树的众数:501. 二叉搜索树中的众数 - 力扣(LeetCode)

和上一题思路一样,都需要一个pre节点来保留前序节点

递归:中序,清空结果集的技巧,遍历一遍即可求众数集合

class Solution {List<Integer> list=new ArrayList<>();int count=0;int maxCount=0;TreeNode pre=null;public int[] findMode(TreeNode root) {if(root==null)return null;findMode(root.left);if(pre==null)count=1;else if(pre!=null&&pre.val==root.val)count++;else count=1;pre=root;if(count==maxCount)list.add(root.val);else if(count>maxCount){maxCount=count;list.clear();list.add(root.val);}findMode(root.right);int[] res=new int[list.size()];for(int i=0;i<list.size();i++){res[i]=list.get(i);}return res;}
}

迭代:

class Solution {public int[] findMode(TreeNode root) {int count=0;int maxCount=0;Stack<TreeNode> st=new Stack<>();List<Integer> list=new ArrayList<>();TreeNode pre=null;if(root!=null)st.push(root);while(!st.isEmpty()){TreeNode node=st.pop();if(node!=null){if(node.right!=null)st.push(node.right);st.push(node);st.push(null);if(node.left!=null)st.push(node.left);}else{TreeNode tmp=st.pop();if(pre==null)count=1;else if(pre!=null&&tmp.val==pre.val)count++;else count=1;pre=tmp;if(count==maxCount)list.add(tmp.val);else if(count>maxCount){maxCount=count;list.clear();list.add(tmp.val);}}}int[] res=new int[list.size()];for(int i=0;i<list.size();i++){res[i]=list.get(i);}return res;}
}

把二叉搜索树转成累加树:538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)

递归:中序,依旧使用pre节点保留前序节点

class Solution {public TreeNode convertBST(TreeNode root) {if(root==null)return null;return inorder(root);}TreeNode pre=null;public TreeNode inorder(TreeNode node){if(node==null)return null;inorder(node.right);if(pre!=null)node.val+=pre.val;pre=node;inorder(node.left);return node;}
}

递归:模拟中序,逻辑相同

class Solution {public TreeNode convertBST(TreeNode root) {if(root==null)return null;Stack<TreeNode> st=new Stack<>();TreeNode pre=null;st.push(root);while(!st.isEmpty()){TreeNode tmp=st.pop();if(tmp!=null){if(tmp.left!=null)st.push(tmp.left);st.push(tmp);st.push(null);if(tmp.right!=null)st.push(tmp.right);}else{tmp=st.pop();if(pre!=null)tmp.val+=pre.val;pre=tmp;}}return root;}
}

二叉树的公共祖先问题

二叉树的公共祖先:236. 二叉树的最近公共祖先 - 力扣(LeetCode)

递归:后序,回溯,找到左子树出现目标值,右子树出现目标值的节点

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

迭代不适合模拟回溯。 

二叉搜索树的公共祖先:235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

因为二叉搜索树的特性,所以比二叉树求最近公共祖先要简单一点。

递归:如果节点的数值在目标区间内就是最近公共祖先

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

迭代:

class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {while(root!=null){if((p.val<=root.val&&q.val>=root.val)||(p.val>=root.val&&q.val<=root.val))return root;else 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;}return null;}
}

二叉搜索树的修改与改造

二叉搜索树中的插入操作:701. 二叉搜索树中的插入操作 - 力扣(LeetCode)

递归:

class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {TreeNode node=new TreeNode(val);if(root==null){root=node;return root;}search(root,node);return root;}public void search(TreeNode root,TreeNode node){if(root.left==null&&node.val<root.val)root.left=node;if(root.right==null&&node.val>root.val)root.right=node;if(node.val>root.val)search(root.right,node);else if(node.val<root.val)search(root.left,node);}
}

 迭代:这里又用到了pre节点记录插入父节点

class Solution {public TreeNode insertIntoBST(TreeNode root, int val) {TreeNode node=new TreeNode(val);if(root==null)return node;TreeNode pre=null;TreeNode Newroot=root;while(Newroot!=null){pre=Newroot;if(Newroot.val>val)Newroot=Newroot.left;else if(Newroot.val<val)Newroot=Newroot.right;}if(pre.val>val)pre.left=node;else if(pre.val<val)pre.right=node;return root;}
}

二叉搜索树中的删除操作:450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

递归:前序,想清楚删除非叶子节点的情况

class Solution {public TreeNode deleteNode(TreeNode root, int key) {if(root==null)return null;if(root.val==key){if(root.left==null)return root.right;else if(root.right==null)return root.left;else{TreeNode tmp=root.right;while(tmp.left!=null){tmp=tmp.left;}tmp.left=root.left;root=root.right;return root;}}else if(root.val<key)root.right=deleteNode(root.right,key);else root.left=deleteNode(root.left,key);return root;}
}

迭代:较复杂

class Solution {public TreeNode deleteNode(TreeNode root, int key) {if (root == null)return null;TreeNode tmp = root;TreeNode pre = null;while (tmp != null) {if (tmp.val > key) {pre = tmp;tmp = tmp.left;} else if (tmp.val < key) {pre = tmp;tmp = tmp.right;} elsebreak;}if (pre == null)return delete(tmp);if (pre.left != null && pre.left.val == key) {pre.left = delete(tmp);}if (pre.right != null && pre.right.val == key) {pre.right = delete(tmp);}return root;}public TreeNode delete(TreeNode node){if(node==null)return null;if(node.right==null)return node.left;TreeNode cur=node.right;while(cur.left!=null){cur=cur.left;}cur.left=node.left;node=node.right;return node;}
}

修剪二叉搜索树:669. 修剪二叉搜索树 - 力扣(LeetCode)

递归:

class Solution {public TreeNode trimBST(TreeNode root,int low,int high){if(root==null)return null;//如果根节点的值小于low,说明根节点左子树都不在范围内,返回修剪好的右子树即可if(root.val<low)return trimBST(root.right,low,high);//如果根节点的值大于high,说明根节点右子树都不在范围内,返回修剪好的左子树即可if(root.val>high)return trimBST(root.left,low,high);//在范围内,递归返回修剪好的左子树和右子树root.left=trimBST(root.left,low,high);root.right=trimBST(root.right,low,high);return root;}
}

 迭代:

class Solution {public TreeNode trimBST(TreeNode root,int low,int high){if(root==null)return null;while(root!=null&&(root.val<low||root.val>high)){if(root.val<low)root=root.right;if(root.val>high)root=root.left;}TreeNode curr=root;while(curr!=null){while(curr.left!=null&&curr.left.val<low){curr.left=curr.left.right;}curr=curr.left;}curr=root;while(curr!=null){while(curr.right!=null&&curr.right.val>high){curr.right=curr.right.left;}curr=curr.right;}return root;}
}

构造二叉搜索树:108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)

分割点就是数组中间位置,这个思路和构造二叉树、求最大二叉树一样。

class Solution {public TreeNode sortedArrayToBST(int[] nums) {return build(nums,0,nums.length);}public TreeNode build(int[] arr,int start,int end){if(start==end)return null;int n=end-start;int index=start+n/2;TreeNode root=new TreeNode(arr[index]);root.left=build(arr,start,index);root.right=build(arr,index+1,end);return root;}
}

http://www.dtcms.com/a/285138.html

相关文章:

  • mysql 字符集不一致导致索引失效问题
  • 为何“白名单媒体”是性价比之选?
  • 2025年视频超高清技术应用全景介绍
  • CSS Grid布局:构建现代网页的强大网格系统
  • Doris 物化视图:原理、使用及常见问题处理
  • Python类型转换,深浅拷贝
  • python的旧时光咖啡厅数据分析管理系统
  • 深入解析Linux进程创建与fork机制
  • Dify:在MacOS系统下Dify的本地部署与使用
  • Android Jetpack 系列(四)DataStore 全面解析与实践
  • RSTP:快速收敛的生成树技术
  • 深入解析SVM:从对偶问题求解到核函数理论
  • [3-03-01].第61节:开发应用 - Seata中的SAGA模式
  • 防止电脑息屏 html
  • Bell不等式赋能机器学习:微算法科技MLGO一种基于量子纠缠的监督量子分类器训练算法技术
  • Java 8 jdk1.8下载及安装教程和环境变量配置
  • 电子电路中的电压符号命名约定
  • 【前端如何利用 localStorage 存储 Token 及跨域问题解决方案】
  • Python网络爬虫之requests库
  • ISL8121IRZ-T 瑞萨电子Renesas高效双路同步降压控制器 【5G基站、AI服务器】专用
  • LIN通信驱动代码开发注意事项
  • 多重共线性Multicollinearity
  • 复合机器人在生物制药实验室上下料搬运案例
  • LeetCode热题100【第二天】
  • 91套商业策划创业融资计划书PPT模版
  • AppTrace:重新定义免填邀请码,解锁用户裂变新高度
  • 50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | PasswordGenerator(密码生成器)
  • 三、了解OpenCV的数据类型
  • 高效去除字符串末尾重复单元的 KMP 前缀函数优化算法实现
  • VR 远程系统的沉浸式协作体验​