前端就该用 JS 刷算法4

526 阅读2分钟

每日一题

二叉树中所有距离为 K 的节点

注意事项

  • dfs 查找目标节点的时候,记得条件深度遍历,否则给 null 加 parent 属性就尴尬了
  • 开始查找距离的时候,记得保存所有走过的节点,防止重复跑
  • 使用 paths 保存走过的节点是因为向上查找过程中,你不晓得自己当前节点是属于父节点的左右哪个节点,做判断更麻烦,不如直接存储走过的节点,更好理解
// https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/
/**
 * 
 * @param {TreeNode} root 根节点
 * @param {TreeNode} target 目标节点
 * @param {number} K 目标距离
 * 
 * @分析
 * 1. 题目已知具有根节点
 * 2. 使用递归的方式求出目标节点,并且标记节点的父节点,辅助向上查找
 * 
 * 
 */
var distanceK = function (root, target, K) {
    const res = []
    const paths = [] // 存储在查找阶段查过的节点
    let targetNode = null
    const dfs = (root) => {
        // 因为是判断递归,且根节点已知存在
        // if (!root) return
        if (root === target) {
            targetNode = root
            return
        }
        if (root.left) {
            root.left.parent = root
            dfs(root.left)
        }
        if (root.right) {
            root.right.parent = root
            dfs(root.right)
        }
    }
    // 求出 targetNode,并为到达该节点前的节点设置 parent
    dfs(root)
    console.log(targetNode)
     
    const findKNode = (root, k) => {
        // 遍历结束或者已经查找过当前节点
        if (!root || paths.indexOf(root) !== -1) return
        paths.push(root)
        if (k === 0) {
            res.push(root.val)
        } else {
            k--
            findKNode(root.left, k, paths)
            findKNode(root.right, k, paths)
        }
    }
    // 向下求节点
    findKNode(targetNode, K)
    // 向上求节点
    while (targetNode.parent && K) {
        // 每次往上走一次,就要减少
        K--
        targetNode = targetNode.parent
        findKNode(targetNode,K)
    }
   
    return res
};

91算法

二分查找

求 x 的平方根

// https://leetcode-cn.com/problems/sqrtx/
/**
 * 向下取整求 x 的平方根
 * @分析
 * 1. 这里最后求向下取整的值,所以其实是求最左侧符合要求值
 */
var mySqrt = function (x) {
    let left = 0
    let right = x
    while (left <= right) {
        const mid = (left + right) >> 1 // 向下取整
        const num = Math.pow(mid, 2)
        if(num === x) return mid
        if (num < x) {
            // 取小了
            left = mid + 1
        } else {
            // 取大了或者直接相等了,右边收缩
            right = mid - 1
        }
    }
    // 因为到了最后,是 right<left,退出循环,所以取小的值
    return right
};
console.log(mySqrt(5))
console.log(mySqrt(6))
console.log(mySqrt(9))
第一个错误版本
// https://leetcode-cn.com/problems/first-bad-version/
// 最外层是为了提供一个检查版本错误的方法
var solution = function (isBadVersion) {
    /**
  * @分析
  * 1. 求第一版的,那就是求最左的版本
  * 2. 这道题默认是必然会有错误出现的
  * 
  * @ 注意
  * 1. 之前都是用 x >> 1 求 x/2 向下取整
  * 2. 实际 >> 是带符号,为了取整,需要用 >>> 无符号右移,对于负数来说无所谓,对正数来说有区别
  * 3. 当然也可以直接用 Math.floor
  */
    return function (n) {
        let left = 1
        let right = n
        while (left<=right){
            // const mid = (left+right)>>1 // 向下取整
            const mid = (left+right)>>>1 // 向下取整
            // const mid = Math.floor((left+right)/2) // 向下取整
            if(isBadVersion(mid)){
                // 如果已经错误,则向左收缩
                right = mid -1
            }else{
                // 如果这个还没有错误,则向右收缩
                left = mid+1
            }
        }
        // 需要判断是否越界了,这个时候
        return left
    };
};