算法杂记(四)

131 阅读1分钟

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战

爬楼梯

解法一

递归:

部分案例超时,原理就是dp(i) = dp(i-2) + dp(i-1),并且已知爬上一格楼梯只有一种方法,爬上两格楼梯有两种,那么我们就可以以此得到f(3),f(4),f(5)...f(n)。

var climbStairs = function(n) {
    if(n === 1){
        return 1
    }
    if(n === 2){
        return 2
    }
    return climbStairs(n-2) + climbStairs(n-1)
};

解法二

保存之前结果:

这里我们也可以不用递归的方式,还是之前那个动态方程式dp(i) = dp(i-2) + dp(i-1),只是呢,这次我们记下每次爬楼梯的方法,再根据前两次和算出最后一个就可以。

var climbStairs = function(n) {
    let dp = [0,1,2]
    for (let i = 3; i <= n ; i++) {
        dp[i] = dp[i-1] + dp[i -2]
    }
    return dp[n]
};

解法三

只保留前两次结果:

这个方法其实是根据上一个方法更改的,因为我们发现,其实我们要求n的值,根本不需要n-2之前的值了,所以我们只保存个 n-1和 n-2的值,再记录每一步的值就行了。

var climbStairs = function(n) {
    if(n === 1) return 1
    if(n === 2) return 2
    let a = 1
    let b = 2
    let c
    for (let i = 3; i <= n ; i++) {
        c = a + b
        a = b
        b = c
    }
    return c
};

路径总和

题目信息

解法一

递归:

用递归的方法去查找路径总和,注意root可能位null,为null直接返回flse即可,叶子节点指的是既没有左子树也没有右子树的结点,到这里只要判断剩下的sum等不等于当前结点的值即可。如果不是,也就是非叶子结点,就去求他的左子树和右子树的路径总和是不是等于当前总和前去当前结点的值。

var hasPathSum = function(root, targetSum) {
    if(root === null) return false
    if(!root.left && !root.right) return targetSum === root.val
    return hasPathSum(root.left,targetSum-root.val) || hasPathSum(root.right,targetSum-root.val)
};

解法二

深度优先(BFS):

我们维护两个队列,一个保存当前结点,一个保存该节点对应的值。有左子树就进队列,右子树也进队列,同时计算对应的值,如果是叶子结点就计算他的值是否为对应路径总和。当队列为空时则无路径总和等于目标值。

var hasPathSum = function(root, targetSum) {
    if(root === null) return false
    let queNode = [root]
    let queVal = [root.val]
    while(queNode.length > 0){
        let curNode = queNode.shift()
        let curVal = queVal.shift()
        if(!curNode.left && !curNode.right){
            if(curVal === targetSum){
                return true
            }
        }
        if(curNode.left){
            queNode.push(curNode.left)
            queVal.push(curVal + curNode.left.val)
        }
        if(curNode.right){
            queNode.push(curNode.right)
            queVal.push(curVal + curNode.right.val)
        }
    }
    return false
};

数组中的第K大元素

解法一

先排序,后取值:

var findKthLargest = function(nums, k) {
    nums.sort((a,b)=>a-b)
    return nums[nums.length - k]
};

解法二

选择排序变种:

我们知道选择排序其实就是,每次选出最大或者最小的数放在排好后的数组的第一位,因此,我们每次求取最大的数,直到第k位为止。

var findKthLargest = function(nums, k) {
    for(let i = 0 ; i < nums.length;i++){
        let maxIndex = i
        for(let j = i+1;j < nums.length;j++){
            if(nums[j] > nums[maxIndex]){
                maxIndex = j
            }
        }
        [nums[maxIndex],nums[i]] = [nums[i],nums[maxIndex]]
        if(i === k-1) return nums[i]
    }
}