算法训练 Day 32

这篇博客探讨了如何使用贪心算法解决LeetCode中的三道经典问题:122.买卖股票的最佳时机II、55.跳跃游戏和45.跳跃游戏II。在股票问题中,通过计算每天与前一天的利润差并累加,实现了最大利润的求解;在跳跃游戏中,通过不断更新可达最远距离来判断是否能到达终点。对于跳跃游戏II,引入了两个覆盖范围的概念,以最小步数达到终点。所有问题的时间复杂度均为O(n),空间复杂度为O(1)。
摘要由CSDN通过智能技术生成

LeetCode 122. 买卖股票的最佳时机 II

题目链接:122. 买卖股票的最佳时机 II

思考:又是一道一眼动规的题目,但其实用贪心的思想会更巧妙一些。我们看一下示例一,在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出,,这笔交易所能获得利润 = 5 - 1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。总利润为 4 + 3 = 7 。

那我们是不是可以将每天与前一天的利润差计算出来,然后将利润大于0的次数直接全部相加,就是这个数组所能获取的最大利润。

Python版本:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        profit = []
        for i in range(1, len(prices)):
            profit.append(prices[i]-prices[i-1])

        res = 0
        for v in profit:
            if v>0:
                res += v
        
        return res

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1)

go版本:

func maxProfit(prices []int) int {
    res := 0
    n := len(prices)-1
    profit := make([]int, n)
    for i:=1; i<len(prices); i++ {
        profit[i-1] = prices[i]-prices[i-1]
    }
    for i:=0; i<n; i++ {
        if profit[i]>0 {
            res += profit[i]
        }
    }
    return res
}

LeetCode 55. 跳跃游戏

题目链接:55. 跳跃游戏

思考:看一下示例,我们发现一个现象:我们不需要知道我们从当前位置跳几步,我们只需要知道我们在当前位置能达到的最远距离即可(在这个点上贪心跟动规很相似),当最远距离大于等于最后一个索引位置就返回true,否则在遍历结束返回false。

Python版本:

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        maxLen = 0
        for i in range(len(nums)):
            if i <= maxLen:
                maxLen = max(maxLen, i+nums[i])

            if maxLen >= len(nums)-1:
                return True

        return False

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1)

go版本:

func canJump(nums []int) bool {
    maxLen := 0
    for i:=0; i<len(nums); i++ {
        if i <= maxLen {
            if nums[i]+i > maxLen {
                maxLen = nums[i]+i
            }
        }
        if maxLen >= len(nums)-1 {
            return true
        }
    }
    return false
}

LeetCode 45. 跳跃游戏 II

题目链接:45. 跳跃游戏 II

思考:此题看似与上一题类似,但实际上要难以实现的多,但跳跃问题最根本的还是看能覆盖到的最远距离。贪心的思路是局部最优:当前可移动距离尽可能多走,如果还没到终点,步数再加一。思路虽然是这样,但在写代码的时候还不能真的就在当前位置能走多远走多远,那样就不知道下一步最远能到哪里了(所以单单只有一个覆盖范围是不够的了,这个后续会细说)。

所以正确的做法是要从覆盖到的最远距离出发,不管怎么跳,覆盖范围内一定是可以跳到的,以最小的步数增加覆盖范围,并且在覆盖范围一旦能覆盖到终点时结束,得到的就是最小步数。

根据前文,单单只有一个覆盖范围是不够的了,所以这里需要统计两个覆盖范围,当前这一步的最大覆盖范围下一步最大的覆盖范围。如果移动下标达到了当前这一步的最大覆盖最远距离了,并且还没有到终点,那么就必须再走一步来增加覆盖范围,直到覆盖范围覆盖了终点。

Python版本:

class Solution:
    def jump(self, nums: List[int]) -> int:
        curLen, nextLen = 0, 0
        res = 0
        n = len(nums)
        for i in range(n):
            nextLen = max(nextLen, nums[i]+i)
            if i==curLen:
                if i < n-1:
                    res += 1
                    curLen = nextLen
                    if nextLen >= n-1:
                        return res
                else:
                    return res
        return res

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( 1 ) O(1) O(1)

go版本:

func jump(nums []int) int {
    curLen := 0
    nextLen := 0
    minStep := 0
    for i:=0; i<len(nums); i++ {
        if nums[i]+i > nextLen {
            nextLen = nums[i]+i
        }
        if i==curLen {
            if i < len(nums)-1 {
                minStep++
                curLen = nextLen
                if nextLen >= len(nums)-1 {
                    break
                }
            } else {
                break
            }
        }
    }
    return minStep
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值