算法-树

21 阅读4分钟
6. 路径总和 === target

参数当前节点和累加和; 没有子节点了到达终点 判断target。哪个有子节点继续累加递归

var hasPathSum = function(root, targetSum) {
    if(!root) return false;
    let rt = false
    
    recurse(root,root.val)
    return rt
  	// 参数是某个节点  到某个节点的和; 注意边界
    function recurse(root, sum) {
        // 到达叶子结点 且总和相等
        if(!root.left && !root.right && (targetSum == sum)){
            rt = true
        }
        if(root.left){
            recurse(root.left,sum+root.left.val)
        }
        if(root.right){
            recurse(root.right,sum+root.right.val)
        }
       
    }
};
10. 求根节点到叶节点数字之和
var sumNumbers = function(root) {
  	// 参数:当前节点 当前节点前的和
    function defs (node, sumNum){
        // 如果当前节点没有 返回0
        if(node === null){
            return 0 // ****
        }
        // 当前节点有值 计算和
        sumNum = 10*sumNum + node.val
      // 是否为叶子节点  叶子节点直接返回和
        if(node.left === null && node.right===null){
            return sumNum
        }
        // 不是叶子节点继续调用这个方法
        return defs(node.left, sumNum) + defs(node.right, sumNum)
    }
    return defs(root,0)
};
14. 二叉树的层序遍历

主要是queue 存储每一层的节点;循环的时候 先拿queue长度再循环;循环时候取值 push queue

var levelOrder = function(root) {
    if(root === null) return []
    let result = [];
    // queue存储每一行 节点
    let queue = [root]
    while (queue.length){
        // 一层长度
        const leveSize = queue.length
        // 一层的值
        const tempArr = []
        for(let i=0;i<leveSize;i++){
          	// 每次循环首部删除
            const current = queue.shift()
            tempArr.push(current.val)
            current.left && queue.push(current.left)
            current.right && queue.push(current.right)
        }
        result.push(tempArr)
    }
    return result
};
26.二叉树的最近公共祖先
var lowestCommonAncestor = function(root, p, q) {
  	// 没值 或者是目标值 直接返回根
    if(!root || root === p || root === q){
        return root
    }
  	
    const left = lowestCommonAncestor(root.left, p, q)
    const right = lowestCommonAncestor(root.right, p, q)
		// 左子树右子树都有  root就是公共祖先
    if(left&&right){
        return root
    }
  	// 只有一个有值 就是left或者right
    return left?left:right
};
28. 两棵二叉搜索树中的所有元素

给你 root1root2 这两棵二叉搜索树。请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序

根据二叉树的特点鲜中序获取到两棵树的值再 两棵树对比排序;排完后没有比较到的直接追加在最后

var getAllElements = function(root1, root2) {
    let arr1=[],arr2=[], result=[]

    // 中序遍历两棵树 再对比值
    function getValue(root, arr){
        if(!root)return;
        root.left&&getValue(root.left, arr)
        arr.push(root.val)
        root.right&&getValue(root.right, arr)
    }

    getValue(root1,arr1)
    getValue(root2,arr2)
    while (arr1.length&&arr2.length){
        if(arr1[0]<arr2[0]){
            result.push(arr1.shift())
        }else {
            result.push(arr2.shift())
        }
    }
    // 没比完的追加在后边
    return [...result, ...arr1,...arr2]
};
49. 二叉搜索树中第K小的元素
// 二叉搜索树的一个关键特性是,对于任何给定的节点,其左子树的所有节点值都小于该节点,而其右子树的所有节点值都大于该节点。
var kthSmallest = function(root, k) {
    let result =[]

    function getVal(node){
        if(node ==null || result.length>=k)return;
        getVal(node.left)
        result.push(node.val)
        getVal(node.right)
    }
    getVal(root)
    return result[k-1]

};
43. 二叉树的最大深度
var maxDepth = function(root) {
    if(root === null){
        return 0
    }
    // 每一层最大值 加 1
    return Math.max(maxDepth(root.left),maxDepth(root.right)) + 1
};
53. 对称二叉树
var isSymmetric = function(root) {
// 判断两个树是否是镜像对称的
  
    function isMirror(left, right) {
      	// 都为null 到 两边的叶子节点 返回true
        if (left === null && right === null) return true;
        // 有一个为null 另一不为null 证明不是对称的
      	if (left === null || right === null) return false;
        //  左子树的右子树 和 右子树的左子树比较 都相同的为对称二叉树
        return (left.val === right.val) && isMirror(left.right, right.left) && isMirror(left.left, right.right);
    }
// 判断一棵树是否是对称的
    return isMirror(root, root);
};
92.二叉树的中序遍历

// 中序遍历 左中右
function inorderTraversal(root) {
    const result = [];
    function traverse(node) {
        if (node === null) return;
        traverse(node.left);  // 遍历左子树
        result.push(node.val); // 访问根节点
        traverse(node.right); // 遍历右子树
    }
    traverse(root);
    return result;
}

// 迭代法
function inorderTraversalIterative(root) {
    const result = [];
    const stack = [];
    let current = root;

    while (current !== null || stack.length > 0) {
        // 先尽可能地访问左子树
        while (current !== null) {
            stack.push(current);
            current = current.left;
        }
        // 当左子树访问完毕,回溯到最近的父节点
        current = stack.pop();
        result.push(current.val); // 访问根节点
        // 转向右子树
        current = current.right;
    }

    return result;
}

// 前序遍历 中左右

function preorderTraversal(root) {
    const result = [];
    function traverse(node) {
        if (node === null) return;
        result.push(node.val); // 访问根节点
        traverse(node.left); // 遍历左子树
        traverse(node.right); // 遍历右子树
    }
    traverse(root);
    return result;
}

// 迭代法

function preorderTraversalIterative(root) {
    if (root === null) return [];
    const result = [];
    const stack = [root];
    
    while (stack.length > 0) {
        const node = stack.pop();
        result.push(node.val); // 访问根节点
        // 先右后左入栈,保证左子树先处理
        if (node.right !== null) stack.push(node.right);
        if (node.left !== null) stack.push(node.left);
    }
    
    return result;
}

// 后续遍历 左右中

function postorderTraversal(root) {
    const result = [];
    function traverse(node) {
        if (node === null) return;
        traverse(node.left); // 遍历左子树
        traverse(node.right); // 遍历右子树
        result.push(node.val); // 访问根节点
    }
    traverse(root);
    return result;
}

// 迭代法

function postorderTraversalIterative(root) {
    if (root === null) return [];
    const result = [];
    const stack = [root];
    let prev = null;

    while (stack.length > 0) {
        const curr = stack[stack.length - 1];
        if (!prev || prev.left === curr || prev.right === curr) {
            if (curr.left) {
                stack.push(curr.left);
            } else if (curr.right) {
                stack.push(curr.right);
            }
        } else if (curr.left === prev) {
            if (curr.right) {
                stack.push(curr.right);
            }
        } else {
            result.push(curr.val);
            stack.pop();
        }
        prev = curr;
    }

    return result;
}

97.翻转二叉树
// 左右节点交换
var invertTree = function(root) {
    resetTree(root)
    function resetTree(node) {
        if(!root){return root}
        let left = node.left 
        let right = node.right
        if(left||right){
            node.right = left
            node.left = right
          	// 交换后继续递归 左右子树
            left&&resetTree(left)
            right&&resetTree(right)
        }
    }
    return root;
};