404.左叶子之和
思路:找左叶子,怎么判断一个节点是左叶子?当前节点的左孩子如果没有左孩子和右孩子,那么这个节点左孩子就是左叶子
因此,只需要遍历二叉树即可,在遍历到中节点的时候,要进行的操作是,判断中节点的左孩子是否为左叶子
我在这题中用的是层次遍历
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
Deque<TreeNode> deque = new LinkedList<>();
if(root==null) return 0;
int res = 0;
deque.offerLast(root);
while(deque.size()!=0){
TreeNode node = deque.pollFirst();
if(node.left!=null&&node.left.left==null&&node.left.right==null){
res += node.left.val;
}
if(node.left!=null){
deque.offerLast(node.left);
}
if(node.right!=null){
deque.offerLast(node.right);
}
}
return res;
}
}
513.找树左下角的值
最后一行最左边的值,这道题用层序遍历时最简单的,而且层序遍历是迭代,用递归反而麻烦hhh
112. 路径总和
回溯,同找树所有路径的那个,只不过是在判断是否要加入的时候,要加一下该路径总和
这个题是要看有没有,找到直接整个函数可以返回了
所以这个题的回溯也可以在主函数里递归来写,不需要统计result
class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if(root==null) return false;
sum -= root.val;
if(sum==0&&root.left==null&&root.right==null) return true;
return hasPathSum(root.left,sum)||hasPathSum(root.right,sum);
}
}
113. 路径总和II
回溯,同找树所有路径的那个,只不过是在判断是否要加入的时候,要加一下该路径总和
这个题是要找到所有,要回溯遍历整个树
106. 从中序与后序遍历序列构造二叉树
通过X序遍历和X序遍历构造回二叉树
注:前序和后序是不能构造回二叉树的
中序:左中右 后序:左右中 因此,拿到两个序的值之后,一起遍历,遍历到出现不同为止,那么中序的不同的第一个就是中间的节点(不中节点就是后续最后一个节点),然后左边的值是左子树的中序遍历,右边的值是右子树的中序遍历。后序遍历也可以获取到左子树的后序遍历和右子树的后序遍历,这样,再次调用这个函数换源左右子树即可,注意边界条件,ok!
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder.length==0) return null;
int rootVal = postorder[postorder.length-1];
TreeNode root = new TreeNode(rootVal);
int res=0;
for(int i=0;i<inorder.length;i++){
if(inorder[i]==rootVal){
res=i;
break;
}
}
int[] inorderleft = (int[])Arrays.copyOfRange(inorder,0,res);
int[] inorderright = (int[])Arrays.copyOfRange(inorder,res+1,inorder.length);
int[] postorderleft = (int[])Arrays.copyOfRange(postorder,0,res);
int[] postorderright = (int[])Arrays.copyOfRange(postorder,res,inorder.length-1);
root.left = buildTree(inorderleft,postorderleft);
root.right = buildTree(inorderright,postorderright);
return root;
}
}
105. 从前序与中序遍历序列构造二叉树
详细思路同上,没有太大差别
654.最大二叉树
这个题就是根据题目要求构造就完了,找好中间节点,左右子树依靠递归完成就行
class Solution {
public int getMax(int[] nums){
int index = 0;
int maxValue = nums[0];
for(int i=1;i<nums.length;i++){
if(nums[i]>maxValue){
index = i;
maxValue = nums[i];
}
}
return index;
}
public TreeNode constructMaximumBinaryTree(int[] nums) {
if(nums.length == 0) return null;
int index = getMax(nums);
TreeNode node = new TreeNode(nums[index]);
int[] left = Arrays.copyOfRange(nums,0,index);
int[] right = Arrays.copyOfRange(nums,index+1,nums.length);
node.left = constructMaximumBinaryTree(left);
node.right = constructMaximumBinaryTree(right);
return node;
}
}
617.合并二叉树
这个题就是按照题意,去生成树,然后三种情况,两个都为null;一个为null,一个不为空;两个都有怎么处理
class Solution {
public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
if(t1==null&&t2==null) return null;
if(t1==null||t2==null) return t1==null?t2:t1;
TreeNode node = new TreeNode(t1.val+t2.val);
node.left = mergeTrees(t1.left,t2.left);
node.right = mergeTrees(t1.right,t2.right);
return node;
}
}
700.二叉搜索树中的搜索
二叉搜索树的性质,中节点左子树的值都小于中节点,右子树都大于中节点
然后再树中找给定的值,就是如果相等就返回root节点,小于就去左子树找,大于就去右子树找
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);
}
}
98.验证二叉搜索树
二叉搜索树的性质,中节点左子树的值都小于中节点,右子树都大于中节点,左右节点也都是二叉搜索树,所以一个二叉搜索树,中序遍历(左中右),获得的遍历结果应该是从小到大的
class Solution {
List<Integer> list = new LinkedList<>();
public void inorder(TreeNode root){
if(root == null) return;
inorder(root.left);
list.add(root.val);
inorder(root.right);
}
public boolean isValidBST(TreeNode root) {
if(root==null) return true;
inorder(root);
for(int i=1;i<list.size();i++){
if(list.get(i-1)>=list.get(i)) return false;
}
return true;
}
}
530.二叉搜索树的最小绝对差
所以根据上题,中序遍历(左中右),获得的遍历结果应该是从小到大的,直接依次计算获得最小差值即可。
我这个没有向上个题一样直接写中序遍历拿一个List,而是使用中序的迭代方法
class Solution {
public int getMinimumDifference(TreeNode root) {
Deque<TreeNode> deque = new LinkedList<>();
TreeNode cur = root;
TreeNode pre = null;
int res = Integer.MAX_VALUE;
while(cur != null || deque.size()!=0){
if(cur!=null){
deque.offerLast(cur);
cur = cur.left;
}else{
cur = deque.pollLast();
if(pre!=null){
res = Math.min(cur.val-pre.val,res);
}
pre = cur;
cur = cur.right;
}
}
return res;
}
}
501.二叉搜索树中的众数
进阶:你可以不使用额外的空间吗?(假设由递归产生的隐式调用栈的开销不被计算在内)
中序遍历的同时,记录最大连续数,当前值连续数,当前值(我在算法里用的是List,实际,不应该可以节省空间的),最大连续值
如果当前值连续数超越最大连续数,替换,使用中序遍历,保证同一个值都出现在一起
class Solution {
List<Integer> list = new LinkedList<>();
int maxCount = 0;
int count = 0;
TreeNode pre = null;
public void searchBST(TreeNode root){
if(root==null) return;
searchBST(root.left);
if(pre == null) count=1;
else if(pre.val==root.val) count++;
else count=1;
pre = root;
if(count == maxCount) list.add(root.val);
if(count> maxCount){
maxCount = count;
list.clear();
list.add(root.val);
}
searchBST(root.right);
}
public int[] findMode(TreeNode root) {
searchBST(root);
int[] res = new int[list.size()];
for(int i=0;i<list.size();i++){
res[i] = list.get(i);
}
return res;
}
}
236. 二叉树的最近公共祖先
思路:如果当前节点是它的公共祖先,那么这两个值一定一个在该节点左边,一个在该节点右边,如果在该节点的同一个子树上,那么它一定不是最近公共祖先
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 left==null?right:left;
else return null;
}
}
235. 二叉搜索树的最近公共祖先
这个题可以依赖二叉搜索树的性质,通过这两个值的大小去判断应该在哪个子树上,如果两个树一大一小,那么这个节点就是最近公共祖先
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root.val>Math.max(p.val,q.val)){
return lowestCommonAncestor(root.left,p,q);
}if(root.val<Math.min(p.val,q.val)){
return lowestCommonAncestor(root.right,p,q);
}
return root;
}
}
701.二叉搜索树中的插入操作
找到合适的位置插入并不难,问题是插入完了之后,你要不要去把这个树变成一个平衡二叉搜索树,如果这个题不需要变成一个平衡二叉搜索树,那你只用找到插入的位置即可,依然是利用搜索树性质,左小右大。
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root==null) return new TreeNode(val);
if(root.val>val){
root.left = insertIntoBST(root.left,val);
}else{
root.right = insertIntoBST(root.right,val);
}
return root;
}
}
450.删除二叉搜索树中的节点
删除节点有三种情况:
1.没找到,那就直接返回
2.删除的节点在叶子,那就直接删除
3.节点不在叶子,这种的是比较麻烦的,需要重构二叉搜索树
3.1节点不在叶子,但是该节点缺了左子树或者右子树,那么直接将不缺的那一边子树上移,补上该节点缺口
3.2节点不在叶子,且左子树右子树均在:选择左子树或右子树根节点作为新节点,用左子树根节点为例,则给右子树在左子树的右支找到一个位置,直接让右子树那一颗树放在该位置即可
class Solution {
public TreeNode insertIntoBST(TreeNode root,TreeNode node) {
if(node==null) return root;
if(root==null) return node;
if(root.val>node.val){
root.left = insertIntoBST(root.left,node);
}else{
root.right = insertIntoBST(root.right,node);
}
return root;
}
public TreeNode deleteNode(TreeNode root, int key) {
if(root==null) return null;
if(root.val==key&&root.left==null&&root.right==null) return null;
else if(root.val==key&&(root.left==null||root.right==null)){
return root.left==null?root.right:root.left;
} else if(root.val==key){
TreeNode right = root.right;
right = insertIntoBST(root.right,root.left.right);
TreeNode node = new TreeNode(root.left.val,root.left.left,right);
return node;
}
if(root.val>key){
root.left = deleteNode(root.left,key);
}else{
root.right = deleteNode(root.right,key);
}
return root;
}
}
669. 修剪二叉搜索树
这个题目的要求是,如果树中元素有相对结构,那么这个结构不应该被改变,所以不要想着去遍历一遍树,然后截一段,再重新生成树,这样会破坏原本结构
因此,思路:递归,递归条件如下
1.如果节点为null 返回null
2.如果节点值大于最大值,则该节点和右子树一定都不满足条件,直接返回左子树处理的结果就行了
如果节点小于最小值,则该节点和左子树一定都不满足条件,直接返回右子树处理的结果就行了
3.如果不满足,说明节点值在区间内,保留该节点,继续处理它的左右子树即可
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if(root==null) return root;
if(root.val>high) return trimBST(root.left,low,high);
if(root.val<low) return trimBST(root.right,low,high);
root.left = trimBST(root.left,low,high);
root.right = trimBST(root.right,low,high);
return root;
}
}
108.将有序数组转换为二叉搜索树
这回是构造二叉树了,而且要求的是二叉平衡搜索树
这个题的难点在于,怎么去找中间节点?保证左右子树平衡?
方法是:使用最中间的位置的值,作为中间节点,值左边左子树,值右边右子树,这样构造出来的树一定是二叉平衡搜索树。一般来讲,大家构造二叉搜索树的时候,也都会取中间节点构造树
class Solution {
public TreeNode traversal(int[] nums,int left,int right){
if(left>right) return null;
int mid = left+(right-left)/2;
TreeNode node = new TreeNode(nums[mid]);
node.left=traversal(nums,left,mid-1);
node.right= traversal(nums,mid+1,right);
return node;
}
public TreeNode sortedArrayToBST(int[] nums) {
TreeNode node = traversal(nums,0,nums.length-1);
return node;
}
}
538.把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
根据累加树定义:我们不难想到,遍历顺序应该是右中左,然后遍历到的节点的值应该加上上一个遍历的节点的值。明白怎么做,就很好做了。
class Solution {
int count=0;
public TreeNode convertBST(TreeNode root) {
if(root==null) return null;
root.right = convertBST(root.right);
count+=root.val;
root.val=count;
root.left = convertBST(root.left);
return root;
}
}