zoukankan      html  css  js  c++  java
  • 树——题解汇总

    二叉搜索树:

    1. 剑指 Offer 36. 二叉搜索树与双向链表 

    题目描述:将二叉搜索树转换为双向循环链表
    解题思路:
    关键点1:二叉搜索树的中序遍历 DFS
    关键点2:双向链表
    关键点3:循环链表
    代码:
    var treeToDoublyList = function(root) {
        // 声明一个空的头结点
        var head =null;
        // 初始化一个pre指向头结点
        var pre=head;
        // 中序遍历二叉搜索树的每一个节点
        function dfs(root){
            if(root==null)return;
            // 遍历左子树
            dfs(root.left);
            // root指向的是当前节点,如果pre为空代表此时指向头结点,需要将head指向当前节点(也就是头结点)
            if(pre==null){
                head=root;
            }else{
                // 前一个节点的后继为当前节点
                pre.right=root;
                // 当前结点的前驱为前一个节点
                root.left=pre;
            }
            // 移动前一个节点到当前节点
            pre=root;
            // 遍历右子树
            dfs(root.right);
        }
        // 注意树为空的情况
        if(root==null)return null;
        dfs(root);
        // 更改头结点的指向
        head.left=pre;
        pre.right=head;
        return head;
    };
    代码

     2. 剑指 Offer 33. 二叉搜索树的后序遍历序列

    题目描述:根据给定数组判断是否是二叉搜索树
    解题思路:
    关键点1:二叉搜索树的后续遍历的最后一个值是根节点 DFS
    关键点2:找到比根节点小的最后一个元素,记录他的索引位置,以此为分界限,此节点向左为左子树,此节点向右(包括此节点为右子树),只有当左右子树也是二叉搜索树才是二叉搜索树
    代码:
    var verifyPostorder = function(postorder) {
        if(postorder.length==0)return true;
        return helper(postorder);
    };
    function helper(arr){
        if(arr.length<=1){
            return true
        }
        var root = arr.pop();
        var i=0;
        for(i=0;i<arr.length;i++){
            if(arr[i]>root){
                break;
            }
        }
        for(var j=i;j<arr.length;j++){
            if(arr[j]<root){return false;}
        }
        return helper(arr.slice(0,i)) && helper(arr.slice(i,arr.length));
    }
    二叉搜索树的后序遍历

     3. 剑指 Offer 07. 重建二叉树

    题目描述:根据给定的先序遍历和中序遍历数组还原二叉树
    解题思路:
    关键点1:前序遍历的首个元素即为根节点 root 的值
    关键点2:在中序遍历中搜索根节点 root 的索引 ,可将中序遍历划分为 [ 左子树 | 根节点 | 右子树 ]
    关键点3:根据中序遍历中的左(右)子树的节点数量,可将前序遍历划分为 [ 根节点 | 左子树 | 右子树 ] 
    关键点4:根据子树特点,我们可以通过同样的方法对左(右)子树进行划分,每轮可确认三个节点的关系 。此递推性质让我们联想到用 递归方法 处理
    代码
    var buildTree = function(preorder, inorder) {
        if(preorder.length==0 || inorder.length==0) return null;
        var root = new TreeNode(preorder[0]);
        var index=inorder.indexOf(root.val);
        var leftArr = inorder.slice(0,index);
        var preL = preorder.slice(1,index+1);
        var rightArr = inorder.slice(index+1);
        var preR = preorder.slice(index+1);
        root.left = buildTree(preL, leftArr);
        root.right = buildTree(preR, rightArr);
        return root;    
    };
    重建二叉树

     4.剑指 Offer 32 - I. 从上到下打印二叉树

    题目描述:广度优先搜索 BFS
    解题思路:
    关键点1:DFS广度优先搜索
    关键点2:将每一层的节点存到数组中
    关键点3:依次弹出每一个节点,将其左右子节点存入数组,将当前节点的值存到结果数组中
    代码
    var levelOrder = function(root) {
        if(root==null){
            return [];
        }
        var curr=[root];
        var result=[];
        while(curr.length){
            var m=curr.shift();
            result.push(m.val)
            if(m.left){
                curr.push(m.left);
            }
            if(m.right){
                curr.push(m.right);
            }
        }
        return result;
    };
    BFS

     5.剑指 Offer 32 - III. 从上到下打印二叉树 III

    题目描述:广度优先搜索 BFS
    解题思路:
    关键点1:BFS广度优先搜索
    关键点2:将每一层的节点存到curr数组中
    关键点3:遍历当前层节点数组,将当前节点的值存到currValue数组中,将当前节点的左右子节点存到nextNode节点数组中
    关键点4:设置标志位,奇数层尾部插入数组,偶数层头部插入数组
    代码
    var levelOrder = function(root) {
        if(root==null) return [];
        var curr=[root];
        // console.log(curr)
        var flag=1;
        var tmpValue=[];
        var nextNode =[];
        var result=[];
        while(curr.length){
            tmpValue=[];
            nextNode=[];
            for(var i=0;i<curr.length;i++){
                if(flag==1){
                    tmpValue.push(curr[i].val);
                }else{
                    tmpValue.unshift(curr[i].val);
                }
                if(curr[i].left){
                    nextNode.push(curr[i].left);
                }
                if(curr[i].right){
                    nextNode.push(curr[i].right);
                }
            }
            flag *=-1;
            result.push(tmpValue);
            if(nextNode){
                curr=nextNode;
            } 
        }
        return result;
    };
    BFS

     6.剑指 Offer 34. 二叉树中和为某一值的路径

    题目描述:返回二叉树中和为某一值的所有路径的数组
    解题思路:
    关键点1:深度优先搜索、先序遍历
    关键点2:当路径和为target并且到达叶子节点时存入结果数组,注意存入数组的浅拷贝,因为路径数组path会一直在发生变化
    关键点3:注意回溯
    代码
    var pathSum = function(root, sum) {
        var res =[];
        // 存放每条路径的数组
        var path=[];
        if(!root)return [];
        function helper(root,target){
            if(root==null)return;
            path.push(root.val);
            target -= root.val;
            // 对于每一个节点都要判断,如果target减为0并且为叶子节点(左右子树均为空)的时候满足要求,就存入结果数组中
            if(target==0 && root.left==null && root.right==null){
                // 这里存放的是path的拷贝,否则path会随着元素的变化而变化
                res.push([...path]);
            }
            helper(root.left,target);
            helper(root.right,target);
            // 注意这里一定要弹出当前元素,这是回溯算法关键的一点
            path.pop();
        }
        helper(root,sum);
        return res;
    };
    };
    二叉树中和为某一值的路径

     7.98. 验证二叉搜索树

    题目描述:返回二叉树中和为某一值的所有路径的数组
    解题思路:
    关键点1:中序遍历
    关键点2:如果是二叉搜索树,判断中序遍历数组是否为升序即可
    关键点3:LeetCode中不要定义全局变量
    代码
    var isValidBST = function(root) {
        var res=[];
        function inOrder(root){
            if(root==null) return [];
            if(root.left){
                inOrder(root.left);
            }
            res.push(root.val);
            if(root.right){
                inOrder(root.right);
            }
        }
        inOrder(root);
        for (let i = 0; i < res.length - 1; i++) {
            if (res[i + 1] <= res[i]) return false;
        }
        return true;
    };
    方法一
    // 方法二 时间上更高效的方法,空间上不需要开辟新数组
    // 也是中序遍历的方法
    // 但是注意在LeetCode上提交的时候不要把 pre变量定义为全局变量
    var isValidBST = function(root){
        var pre=-Infinity;
        function helper(root){
            if(root==null)return true;
            if(!helper(root.left)){
                return false;
            }
            if(root.val<=pre){
                return false;
            }
            pre=root.val;
            if(!helper(root.right)){
                return false;
            }
            return true;
        }
        return helper(root);
    }
    改进的方法二

     8.96. 不同的二叉搜索树

    题目描述:给定一个整数 n,求以 1 ... n 为节点组成的二叉搜索树有多少种 (理解不够深刻)
    解题思路:
    关键点1:动态规划、递归
    关键点2:我们可以遍历每个数字 ii,将该数字作为树根,将 1 cdots (i-1)1⋯(i−1) 序列作为左子树,将 (i+1) cdots n(i+1)⋯n 序列作为右子树。
         接着我们可以按照同样的方式递归构建左子树和右子树
    代码
    var numTrees = function(n) {
        // 开辟一个数组,用0初始化
        var dp= new Array(n+1).fill(0);
        // 初始化
        dp[0]=1;
        dp[1]=1;
        // 分别以每个元素i为根节点值
        for(var i=2;i<=n;i++){
            for(var j=1;j<=i;j++){
                dp[i] += dp[j-1]*dp[(i-j)];
            }
        }
        return dp[n];
    };
    View Code

     9.1382. 将二叉搜索树变平衡

    题目描述:如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过 1 ,我们就称这棵二叉搜索树是 平衡的
    解题思路:
    关键点1:二叉树的重构、中序遍历
    关键点2:中序遍历有序数组,然后奖盖有序数组重构为二叉平衡树
    关键点3:重构的时候为保证左右子树高度差小于等于1,取数组中间值作为根节点,然后递归求得左右子树
    代码
    var balanceBST = function(root) {
        var res = [];
        function dfs(root){
            if(root==null) return null;
            dfs(root.left);
            res.push(root.val);
            dfs(root.right);
        }
        dfs(root);
        function reBuild(arr){
            if(arr.length==0){
                return null;
            }
            if(arr.length==1){
                return new TreeNode(arr[0]);
            }
            var mid=Math.floor(arr.length/2);
            var newRoot = new TreeNode(arr[mid]);
            newRoot.left = reBuild(arr.slice(0,mid));
            newRoot.right = reBuild(arr.slice(mid+1));
            return newRoot;
        }
        return reBuild(res);
    };
    View Code

     10.701. 二叉搜索树中的插入操作

    题目描述:二叉搜索树的巨大优势就是:在平均情况下,能够在 O(logN) 的时间内完成搜索和插入元素
    解题思路:
    关键点1:若 val > node.val,插入到右子树。
    关键点2:若 val < node.val,插入到左子树。
    代码
    // 递归
    var insertIntoBST = function(root, val) {
        if(root==null) return new TreeNode(val);
        if(root.val < val){
            root.right = insertIntoBST(root.right,val);
        }else{
            root.left = insertIntoBST(root.left,val);
        }
        return root;
    };
    // 迭代
    var insertIntoBST = function(root, val) {
        if(root==null) return new TreeNode(val);
        var parent = root,p=root;
        while(p!=null){
            parent = p;
            p=p.val<val ? p.right:p.left;
        }
        if(parent.val<val){
            parent.right = new TreeNode(val);
        }else{
            parent.left = new TreeNode(val);
        }
        return root;
    };
    二叉搜索树插入节点

     11.450. 删除二叉搜索树中的节点

    题目描述:二叉搜索树的巨大优势就是:在平均情况下,能够在 O(logN) 的时间内完成搜索和插入元素
    解题思路:分为三种情况:
    1.如果要删除的节点在左子树,递归左子树
    2.如果要删除的节点在右子树,递归右子树
    3.要删除的节点为根节点:再分情况判断左右子树是否为空,当都不为空的时候,找到右子树上的最小节点,将根节点的值替换为这个最小值,然后删除这个最小节点
    var deleteNode = function(root, key) {
        if(root==null){
            return root;
        }
        // 要删除的节点在右子树
        if(root.val<key){
            root.right = deleteNode(root.right,key);
        }else if(root.val>key){
            // 要删除的节点在左子树
            root.left = deleteNode(root.left,key);
        }else{
            // 要删除的节点为根节点
            // 如果左右子树均为空
            if(root.left==null && root.right==null){
                root = null;
            }
            // 如果右子树为空
            else if(root.right==null && root.left!=null){
                root = root.left;
            } 
            // 如果左子树为空
            else if(root.left==null && root.right!=null){
                root = root.right;
            }else {
                // 如果左右子树均不为空
                var tmp = root.right;
                // 找到右子树上最小的数
                while(tmp.left!==null){
                    tmp = tmp.left;
                }
                // 将根节点的值替换为这个最小的值
                root.val=tmp.val;
                // 删除有字数上这个最小的值
                root.right = deleteNode(root.right, root.val);
            }
            
        }
        return root;
    };
    二叉搜索树删除节点
  • 相关阅读:
    scala-class
    uva-10422-骑士-搜索题
    HDU 5724
    HDU 5728
    CodeForces 414B
    CodeForces 698A
    Codeforces Round #363 (Div. 2)
    BestCoder 2nd Anniversary 1001 Oracle
    BestCoder 2nd Anniversary 1002 Arrange
    HDU 4798
  • 原文地址:https://www.cnblogs.com/ccv2/p/13625566.html
Copyright © 2011-2022 走看看