【刷题系列】二叉树

系列汇总:《刷题系列汇总》



——————《剑指offeer》———————

1. 二叉树的镜像

  • 题目描述:操作给定的二叉树,将其变换为源二叉树的镜像。
    在这里插入图片描述
  • 我的思路:【递归】下面代码通不过,原因是在进行了第3行后,节点的结果改变了,没达到预期结果
    public TreeNode Mirror (TreeNode pRoot) {
        if(pRoot == null) return null;
        pRoot.left = Mirror(pRoot.right);
        pRoot.right = Mirror(pRoot.left);
        return pRoot;
    }
    
  • 解决措施(15%):将Mirror(pRoot.right)和Mirror(pRoot.left)都先暂存,再取用
import java.util.*;
public class Solution {
    public TreeNode Mirror (TreeNode pRoot) {
        if(pRoot == null) return null;
        TreeNode right = Mirror(pRoot.right);
        TreeNode left = Mirror(pRoot.left);
        pRoot.left = right;
        pRoot.right = left;
        return pRoot;
    }
}
  • 优秀思路(25%):【递归】
import java.util.*;
public class Solution {
    public TreeNode Mirror (TreeNode pRoot) {
        // 递归三要素:
        // 1、停止条件
        if(pRoot == null) return pRoot;
        // 2、基本操作
        TreeNode temp= pRoot.left;
        pRoot.left = pRoot.right;
        pRoot.right = temp;
        // 3、递归方式:注意这里有返回值的函数也可以进行不返回的递归
        Mirror(pRoot.left);
        Mirror(pRoot.right);
        return pRoot;
    }
}

2. 二叉树的深度(需重写)

  • 题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
  • 我的思路(89%):【BFS】利用队列先入先出的特点,每次抛出某层全部的节点,count+1。
import java.util.*;
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root == null) return 0;
        int count = 0;
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
            int size = q.size();
            count++;
            while(size-- > 0){  //每次抛出一层的所有节点
                TreeNode cur = q.poll();
                if(cur.left != null) q.add(cur.left);
                if(cur.right != null) q.add(cur.right);
            }
        }
        return count;
    }
}
  • 优秀思路(89%):【DFS】
import java.util.*;
public class Solution {
    public int TreeDepth(TreeNode root) {
        if(root==null) return 0;
        int left=TreeDepth(root.left);
        int right=TreeDepth(root.right);
        return Math.max(left,right)+1;
    }
}

3. 对称的二叉树(需重写)

  • 题目描述:请实现一个函数,用来判断一棵二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
  • 我的思路(85%):【BFS】利用队列遍历每层节点,每层的节点值保存在 stack 里判断是否对称(若当前值和堆顶值相同则pop,否则将当前值push),某层stack不为空则非对称。剪枝策略:(除第一层外)某层有奇数个非空节点,一定非对称
import java.util.*;
public class Solution {
    boolean isSymmetrical(TreeNode pRoot) {
        if(pRoot == null) return true;
        Queue<TreeNode> q = new LinkedList<>();
        Stack<Integer> stack;
        q.add(pRoot);
        int layer = 0;
        TreeNode tempNode = new TreeNode(0);
        while(!q.isEmpty()){
            layer++;
            int size = q.size();
            stack = new Stack<>();
            // (除第一层外)某层有奇数个非空节点,一定非对称
            if(size % 2 != 0 && layer != 1) return false; // 奇数个节点
            while(size-- > 0){
                TreeNode node = q.poll();
                // 分别加入node.left和node.right
                // 空节点的值用-100代替
                for(int i = 0;i<2;i++){
                    if(i == 0) tempNode = node.left;
                    if(i == 1) tempNode = node.right;
                    if(tempNode != null){
                        q.add(tempNode);
                        if(stack.empty() || tempNode.val != stack.peek()){
                            stack.push(tempNode.val);
                        }else{
                            stack.pop();
                        }
                    }else{
                        if(stack.empty() || -100 != stack.peek()){
                            stack.push(-100);
                        }else{
                            stack.pop();
                        }
                    }
                }
            }
            if(!stack.empty()) return false;
        }
        return true;
    }
}
  • 优秀思路(85%): 【递归】递归的比较两节点是否相同,总共三种情况:① 左右子树都为空:对称; ② 其中一边为空:不对称;③ 左右子树val值不同:不对称。比较两节点时,需比较最左-最右 & 中左-中右(核心)。
import java.util.*;
public class Solution {
    boolean isSymmetrical(TreeNode pRoot){
        if(pRoot == null) return true;
        return helper(pRoot.left,pRoot.right);
    }
    // 辅助函数:判断是否对称
    boolean helper(TreeNode left,TreeNode right){
        if(left == null && right == null) return true; // 左右子树都为空:对称
        if(left == null || right == null) return false; // 其中一边为空:不对称
        if(left.val != right.val) return false; // 左右子树val值不同:不对称
        // 最左-最右须相同,中左-中右须相同
        return helper(left.left,right.right) && helper(left.right,right.left);
    }
} 

4. 二叉树的下一个结点

  • 题目描述:给定一个二叉树其中的一个结点,请找出中序遍历顺序**(左根右)**的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针。
    在这里插入图片描述

  • 优秀思路:【还原二叉树】既然给了二叉树的某个结点,且二叉树存储着指向父结点的指针(next),那我们可以:① 先找到根节点;② 再对树进行中序遍历;③ 最后根据中序遍历结果找到给定结点的下一结点(特殊情况:如果给出的节点本来就是最后一个节点,则其下一个节点为null)

import java.util.*;
public class Solution {
    ArrayList<TreeLinkNode> list = new ArrayList<>();
    public TreeLinkNode GetNext(TreeLinkNode pNode){
        // 1、寻找根节点
        TreeLinkNode root = pNode;
        while(root.next != null){
            root = root.next;
        }
        // 2、寻找中序遍历
        MidOrder(root);
        // 3、寻找下一节点
        for(int i = 0;i < list.size();i++){
            if(list.get(i) == pNode){
                // 如果给出的节点本来就是最后一个节点,则其下一个节点为null
                return i == list.size()-1 ? null:list.get(i+1);
            }
        }
        return null;
    }
    private void MidOrder(TreeLinkNode pNode){
        if(pNode != null){
            MidOrder(pNode.left);
            list.add(pNode);
            MidOrder(pNode.right);
        }
    }
}

5. 从上往下打印二叉树

  • 题目描述:从上往下打印出二叉树的每个节点,同层节点从左至右打印。
  • 我的思路(优秀,90%)
import java.util.*;
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> res = new ArrayList<>();
        if(root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        int layerSize = 0;
        TreeNode temp = root;
        while(!q.isEmpty()){
            layerSize = q.size();
            while(layerSize-- > 0){ //这里其实没必要,下面会优化
                temp = q.poll();
                res.add(temp.val);
                if(temp.left != null) q.add(temp.left);
                if(temp.right != null) q.add(temp.right);
            }
        }
        return res;
    }
}
  • 我的思路优化:由于队列先进先出的特性以及题目输出的要求,不用考虑每次输出一层,按顺序往里加就行。
import java.util.*;
public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
        ArrayList<Integer> res = new ArrayList<>();
        if(root == null) return res;
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        TreeNode temp = root;
        while(!q.isEmpty()){
            temp = q.poll();
            res.add(temp.val);
            if(temp.left != null) q.add(temp.left);
            if(temp.right != null) q.add(temp.right);
        }
        return res;
    }
}

6. 二叉树中和为某一值的路径

  • 题目描述:输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。
  • 我的思路(97%,不稳定):【递归】定义一个当前和和当前字符串list,满足条件则添加到res里。需要注意两点:
    • 1、递归的添加条件不能放dfs开头,这样是没有由于每次开头无运算,会导致重复添加;
    • 2、当前字符串list在当前递归完后要恢复到上一状态;
    • 3、题目要求结尾必须是叶节点,即后面再无节点 curNode.left == null && curNode.right == null
public class Solution {
    ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
        if(root == null || target < root.val) return res;
        ArrayList<Integer> tempRes = new ArrayList<>();
        dfs(root,tempRes,0,target);
        return res;
    }
    // 递归
    void dfs(TreeNode curNode,ArrayList<Integer> tempRes,int curSum,int target){
        if(curNode == null || curSum > target) return;
        tempRes.add(curNode.val);
        curSum += curNode.val;
        // 注意必须是叶节点
        if(curSum == target && curNode.left == null && curNode.right == null)res.add(new ArrayList<Integer>(tempRes)); // 为避免重复添加,这一段不能放在dfs开头,必须保证每次都要经过运算后符合条件再添加
        dfs(curNode.left,tempRes,curSum,target);
        dfs(curNode.right,tempRes,curSum,target);
        tempRes.remove(tempRes.size()-1); //这里很必须,list自身的特性,会一起改变,所以需要删除最后一位
    }
}
  • 优秀思路(92%,稳定)

7. 按之字形顺序打印二叉树

  • 题目描述:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。
  • 我的思路(优秀,99%):【双栈法】利用栈后入先出的特性,一个栈保存当前层节点,一个栈保存下一层节点。入栈规则如下:
    • 当前层为奇数层时:下一层为从左到右输出,故从右到左入栈即可。
    • 当前层为偶数层时:下一层为从右到左输出,故从左到右入栈即可。
import java.util.*;
public class Solution {
    public ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> res = new ArrayList<>(); // 总结果
        ArrayList<Integer> layerRes; // 每层的结果
        if(pRoot == null) return res;

        Stack<TreeNode> curLayer = new Stack<>(); // 当前层节点
        Stack<TreeNode> nextLayer;// 下一层节点
        curLayer.push(pRoot);
        int nLayer = 0;
        while(!curLayer.empty()){
            nLayer++;
            int size = curLayer.size();
            layerRes = new ArrayList<>();
            nextLayer = new Stack<>(); // 重置nextLayer
            while(size-- > 0){
                TreeNode tempNode = curLayer.pop();
                layerRes.add(tempNode.val);
                if(nLayer % 2 == 0){ // 偶数层:下一层为从左到右输出,故从右到左入栈即可
                    if(tempNode.right != null) nextLayer.push(tempNode.right);
                    if(tempNode.left != null) nextLayer.push(tempNode.left);
                }else{ //奇数层:下一层为从右到左输出,故从左到右入栈即可
                    if(tempNode.left != null) nextLayer.push(tempNode.left);
                    if(tempNode.right != null) nextLayer.push(tempNode.right);
                }
            }
            curLayer = nextLayer; // 更新下一层
            res.add(layerRes);
        }
        return res;
    }
}
  • 优秀思路1:【队列】在偶数层将list反转一下就行,调用Collection.reverse()
  • 优秀思路2:【队列】也是偶数层反转,不过反转方式不用掉包,而是在list添加元素时引入插入位置list.add(index, T),偶数层时将index设置为0,则可保证倒序插入

8. 二叉搜索树的后序遍历序列

  • 题目描述:输入一个整数数组,判断该数组是不是某二叉搜索树后序遍历的结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。(ps:我们约定空树不是二叉搜素树
  • 优秀思路:【递归】首先要明确两点:① 二叉搜索树的性质就是左子树的节点val总是小于根节点val,右子树总是大于根节点val;② 要明确中序遍历的顺序是【左-右-根】。所以利用递归,每次找出根节点(最后一位),利用大小关系找到右子树的起点,判断右子树中有无比根节点val更大的值,若有则不是中序遍历。
public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
        if(sequence == null || sequence.length == 0)return false;//空子树
        return  helpVerify(sequence, 0, sequence.length-1);
    }
    public boolean helpVerify(int [] sequence, int start, int root){
        if(start >= root) return true; // 递归停止条件:子树遍历完成
        // 1、取出根节点
        int rootValue = sequence[root];
        // 2、找右子树起点:注意右子树可以为空
        int i;
        for(i = start;i < root;i++){
            if(sequence[i] > rootValue){ 
                break;
            }
        }
        // 3、若有右子树,则判断右子树是否全部大于根节点
        //    若无右子树,则i = root-1,则此循环也不会进行
        for(int j = i;j < root;j++){
            if(sequence[j] < rootValue) return false;
        }
        // 判断左子树和右子树
        return helpVerify(sequence,start,i-1) && helpVerify(sequence,i,root-1);
    }
}

9. 树的子结构(需重写)

  • 题目描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
  • 我的思路(80%):【队列+递归】通过队列,从A中val与B根节点相同的节点,只要发现就从该节点开始进行一次比较。比较用递归实现,每次比较当前节点的左右两子节点的值。需要注意的有两点:① 比较都是以B为标准进行比较,因为A中包含很多无关结构;② 写循环有一个要点就是,边界条件一定要放最前面,防止越界。
import java.util.*;
public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1 == null || root2 == null) return false;
        // 在A中找到B的根节点
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root1);
        boolean res = false;
        while(!q.isEmpty()){
            TreeNode cur = q.poll();
            // 发现val与root2根节点相同的就比较一次
            if(cur.val == root2.val){
                res = res || helper(cur,root2); //最终只要有一次比较成功就成功
            }
            if(cur.left != null) q.add(cur.left);
            if(cur.right != null) q.add(cur.right);
        }
        return res;
    }
    
    // 比较两根节点val相同的树是否含包含关系
    private boolean helper(TreeNode cur,TreeNode root2){
        if(root2 == null) return true; // 遍历到了最后
        // 以root2为基准进行比较
        // 边界类的条件一定要放最前面,否则会越界
        if(root2.left != null){
            if(cur.left == null || root2.left.val != cur.left.val) return false;
        }
        if(root2.right != null){
            if(cur.right == null || root2.right.val != cur.right.val) return false;
        }
        return helper(cur.left,root2.left) && helper(cur.right,root2.right);
    }
}
  • 优秀思路(92%):【递归】省去队列辅助搜索,直接在递归的过程中进行搜索
public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1 == null || root2 == null) return false;
        return check(root1,root2) || HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2);
    }
    public boolean check(TreeNode root1,TreeNode root2){
        if(root2 == null) return true;//比较到了某空节点或最后
        if(root1 == null || root1.val != root2.val) return false;// 两节点值不同
        return check(root1.left,root2.left) && check(root1.right,root2.right);
    }
}

10. 二叉搜索树的第k个结点(需重写)

  • 题目描述:给定一棵二叉搜索树,请找出其中的kTreeNode结点。
  • 我的思路(97%):【最小堆】① 建立最小堆存储节点:根据节点val升序排列;② 输出结果。
import java.util.*;
public class Solution {
    // 建立最小堆存储节点:根据节点val升序排列
    PriorityQueue<TreeNode> heap = new PriorityQueue<>(new Comparator<TreeNode>(){
        public int compare(TreeNode n1,TreeNode n2){
            return n1.val-n2.val; // 根据节点val升序排列
        }
    });
    // 主函数
    TreeNode KthNode(TreeNode pRoot, int k) {
        if(pRoot == null || k < 1) return null;
        // 1、保存所有节点
        saveNode(pRoot);
        TreeNode res = pRoot;
        // 2、输出结果
        while(k-- > 0) res = heap.poll();
        return res;
    }
    // 保存节点
    private void saveNode(TreeNode pRoot){
        if(pRoot != null){
            heap.add(pRoot);
            saveNode(pRoot.left);
            saveNode(pRoot.right);
        }
    }
}
  • 优秀思路:【递归】二叉搜索树的中序遍历特点:递增序列。所以从最左下角的节点开始寻找即可,寻找顺序:左-根-右
public class Solution {
    TreeNode tar = null; // 结果
    int count = 0;
    TreeNode KthNode(TreeNode pRoot, int k) {
        if (pRoot == null || k <= 0) return null;
        preOrder(pRoot,k);
        return tar;
    }
    
    public void preOrder(TreeNode pRoot,int k){
        if(pRoot == null || count > k) return; // count > k 是为了避免已寻找到目标节点后的无效搜索
        preOrder(pRoot.left,k); // 左
        count++;
        if(count == k) {
            tar = pRoot; // 根
        }
        preOrder(pRoot.right,k); // 右
    }
}

11. 序列化二叉树(需重写)

  • 题目描述:请实现两个函数,分别用来序列化反序列化二叉树,不对序列化之后的字符串进行约束,但要求能够根据序列化之后的字符串重新构造出一棵与原二叉树相同的树。**二叉树的序列化(树→序列)**是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树等遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以 表示一个结点值的结束(value!)。**二叉树的反序列化(序列→树)**是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。
  • 优秀思路:【分割+递归】分两步:① 保存节点值:保存时用都逗号分隔开,方便还原时进行分割;② 还原二叉树:先分割出所有的节点值,再递归还原。
public class Solution {
    int i = 0;
    // 层序遍历保存节点值
    // 利用逗号隔开所有节点值
    String Serialize(TreeNode root) {
        StringBuilder s = new StringBuilder();
        Serialize(root,s);
        return s.substring(0,s.length() - 1);
    }
    void Serialize(TreeNode root,StringBuilder str) {
        if (root == null) {
            str.append("#,");
            return;
        }
        str.append(root.val + ","); // StringBuilder可以直接append数字
        Serialize(root.left,str);
        Serialize(root.right,str);
    }
    // 还原二叉树
    TreeNode Deserialize(String str) {
        String[] strs = str.split(",");// 利用逗号分隔符获得节点值矩阵
        return Deserialize(strs);
    }
    
    TreeNode Deserialize(String[] strs) {
       String s = strs[i++];
       if ("#".equals(s)) {
           return null;
       }
        // 递归中如果需要返回值,则返回值最好时每轮都新建的更方便
       TreeNode root = new TreeNode(Integer.parseInt(s));
       root.left = Deserialize(strs);
       root.right = Deserialize(strs);
       return root;
    }
}

——————《LeectCode》———————

1. 把二叉搜索树转换为累加树

  • 题目描述:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
  • 我的思路:【反中序遍历】遗憾的是没实现,下面代码没通过!
class Solution {
    TreeNode res = new TreeNode(0);
    TreeNode index = res;
    int sum = 0;
    public TreeNode convertBST(TreeNode root) {
        if(root == null) return null;
        dfs(root);
        return res;
    }
    private TreeNode dfs(TreeNode root){
        if(root == null) return null;
        index.right = dfs(root.right);
        sum += root.val;
        TreeNode temp = new TreeNode(sum);
        index = temp;
        index.left = dfs(root.left);
        return temp;
    }
}
  • 优秀思路:【递归】明确题意后,其实只需修改节点的值即可,而不需要重新构造节点
class Solution {
    int sum = 0;
    public TreeNode convertBST(TreeNode root) {
        if (root != null) {
            //遍历右子树
            convertBST(root.right);
            //遍历顶点:注意只修改节点值即可,不用改变节点
            sum += root.val;
            root.val = sum;
            //遍历左子树
            convertBST(root.left);
            return root;
        }
        return null;
    }
}

2. BiNode(需重写)

  • 题目描述:二叉树数据结构TreeNode可用来表示单向链表(其中left置空,right为下一个链表节点)。实现一个方法,把二叉搜索树转换为单向链表,要求依然符合二叉搜索树的性质,转换操作应是原址的,也就是在原始的二叉搜索树上直接修改。返回转换后的单向链表的头节点。

  • 优秀思路:【递归中序遍历】注意条件设置的原因

class Solution {
    TreeNode res;
    TreeNode pre;
    public TreeNode convertBiNode(TreeNode root) {
        convertBiNodeHelper(root);
        return res;
    }
    // 中序遍历。res存储最终返回的节点,即中序遍历的第一个节点
    public void convertBiNodeHelper(TreeNode root) {
        if(root != null){ // 这一句就保证了可以一直找到最底层
            convertBiNodeHelper(root.left);
            if(res == null){
                res = root; // 由于是中序遍历,可以保证将最底层的最左节点赋给res
            }
            //初始pre为空,先将pre指向第一个遍历的节点,之后遍历到第二个及之后的节点时
            //将pre的右指针指向该节点,然后pre再指向该节点,然后再将pre左指针置为null
            if(pre != null){ // 这个条件就跳过了头节点,即不需要其他节点的右边指向头节点
                pre.right = root; // 上一节点的右边指向本节点
            }
            pre = root; // 更新上一节点
            pre.left = null; // 上一节点的左边置空
            convertBiNodeHelper(root.right);
        }
    }
}

3. 将二叉搜索树变平衡

  • 题目描述:给你一棵二叉搜索树,请你返回一棵 平衡后 的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过 1 ,我们就称这棵二叉搜索树是 平衡的 。如果有多种构造方法,请你返回任意一种。
  • 优秀思路:【中序遍历+递归】① 中序遍历拆开二叉搜索树,并存储各节点val值;② 递归的寻找中间节点作为父节点,进行二叉树还原并平衡化
class Solution {
    List<Integer> midList = new ArrayList<>();
    public TreeNode balanceBST(TreeNode root) {
        midOrderVal(root);
        return buildBalancedTree(midList,0,midList.size()-1);
    }
    // 拆树:中序遍历
    void midOrderVal(TreeNode root){
        if(root.left != null) midOrderVal(root.left);
        midList.add(root.val);
        if(root.right != null) midOrderVal(root.right);
    }
    // 建树
    TreeNode buildBalancedTree(List<Integer> midList,int start,int end){
        if(start > end) return null;
        int mid = (start+end) >> 1;
        TreeNode tree = new TreeNode(midList.get(mid));
        tree.left = buildBalancedTree(midList,start,mid-1);
        tree.right = buildBalancedTree(midList,mid+1,end);
        return tree;
    }
}

4. 二叉搜索子树的最大键值和(需重写)

  • 题目描述:给你一棵以 root 为根的 二叉树 ,请你返回 任意 二叉搜索子树的最大键值和。二叉搜索树的定义如下:
    • 任意节点的左子树中的键值都 小于 此节点的键值。
    • 任意节点的右子树中的键值都 大于 此节点的键值。
    • 任意节点的左子树和右子树都是二叉搜索树。
  • 优秀思路:【递归】自顶向下递归的判断每个节点开始的子树是否为BST(二叉搜索树), 若是则计算该子树的节点和。
class Solution {
    int res = 0;
    public int maxSumBST(TreeNode root) {
        maxSumBST_Helper(root);
        return res;
    }
  
    // 找出所有的BST开始节点,计算子树值和
    private void maxSumBST_Helper(TreeNode node) {
        // 这个节点是BST,直接求和了
        if (isBST(node, Integer.MIN_VALUE, Integer.MAX_VALUE)) {
            // 是二叉搜索树,求节点和,节点和的最优解,肯定在子节点求和的过程中
            sumNodeValue(node);
            return;
        }
        // 不是BST,递归进入左右子树
        maxSumBST_Helper(node.left);
        maxSumBST_Helper(node.right);
    }

    // 判断root为根节点的树是否是二叉搜索树
    private boolean isBST(TreeNode root, int min, int max) {
        if (root == null) {
            return true;
        }
        return min < root.val && root.val < max && isBST(root.left, min, root.val) && isBST(root.right, root.val, max);
    }

    // 以node为root的节点求和
    private int sumNodeValue(TreeNode node) {
        if (node == null) {
            return 0;
        }
        // 二叉搜索树节点和的最大值,一定在子节点中会出现
        int sum = node.val + sumNodeValue(node.left) + sumNodeValue(node.right);
        // 这里记录结果的最大值
        res = Math.max(res, sum);
        return sum;
    }
}

5. 1214(Plus题,需会员)

  • 题目描述
  • 优秀思路

6. 把二叉搜索树转换为累加树

  • 题目描述:给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
  • 优秀思路:【反中序遍历】修改节点值即可
class Solution {
    int sum = 0;
    public TreeNode bstToGst(TreeNode root) {
        dfs(root);
        return root;
    }
    // 反中序遍历
    void dfs(TreeNode root){
        if(root == null) return;
        dfs(root.right);
        sum += root.val;
        root.val = sum;
        dfs(root.left);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值