算法刷题打卡028 | 贪心算法2

感觉不少贪心算法的题目都能用动态规划求解。

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

题目链接:122. 买卖股票的最佳时机 II - 力扣(Leetcode)

这道题买卖股票不限制次数,贪心贪的就是股票正的价格差,局部极小值入手,价格即将下跌之前的极大值出手:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        if n < 2:
            return 0  # 无法进行交易
        idx, total = 0, 0
        # 方法是找上升区间
        while idx < n:
            while idx < n - 1 and prices[idx] > prices[idx + 1]:
                idx += 1
            min_price = prices[idx]
            while idx < n - 1 and prices[idx] < prices[idx + 1]:
                idx += 1
            total += prices[idx] - min_price
            idx += 1
        
        return total

只要一次遍历就能不断累积上升区间的最大利润,时间复杂度是O(n),空间复杂度是O(1)。而代码随想录讲解中将上升区间分解,直接在for循环遍历过程中累加差值为正的利润:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        if n < 2:
            return 0  # 无法进行交易
        total = 0
        for i in range(1, n):
            total += max(0, prices[i] - prices[i-1])
        return total

LeetCode 55 跳跃游戏

题目链接:55. 跳跃游戏 - 力扣(Leetcode)

因为题目只求是否能够到达最后一个下标,而不关心是怎么跳的,只需要判断在遍历过程中能跳的最远范围是否会覆盖最后一个下标:

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        if len(nums) == 0:
            return True
        cover = 0
        i = 0
        while i < cover + 1:
            cover = max(i + nums[i], cover)  # 更新当前位置的覆盖范围
            if cover >= len(nums) - 1:
                return True
            i += 1
        return False

LeetCode 45 跳跃游戏II

题目链接:45. 跳跃游戏 II - 力扣(Leetcode)

这道题比跳跃游戏多了最小步数的限制条件,之前做题想用动态规划求解,但两重for循环直接超时了:

class Solution:
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        dp = [0 for _ in range(n)] # dp数组含义:跳到下标为i处的最小跳跃次数
        for i in range(1, n):
            min_step = float('inf')
            for j in range(i):
                if nums[j] >= i - j:
                    # i在j的可跳跃范围
                    min_step = min(min_step, dp[j] + 1)
            dp[i] = min_step
        return dp[n-1]
        # dp超时...

看讲解是同样以覆盖范围的角度解题,但除了当前的最大覆盖范围,还要考虑下一步,“如果移动下标达到了当前这一步的最大覆盖最远距离,还没有到终点的话,那么就必须再走一步来增加覆盖范围,直到覆盖范围覆盖了终点。”

class Solution:
    def jump(self, nums: List[int]) -> int:
        n = len(nums)
        # 贪心
        curdis, nextdis = 0, 0
        ans = 0
        for i in range(n):
            nextdis = max(nextdis, i + nums[i])
            if i == curdis:
                if curdis < n - 1:
                    ans += 1
                    curdis = nextdis
                    if nextdis >= n - 1:
                        break  # 无需再走
                else:
                    break  # 当前已经覆盖到n-1的位置
        return ans

贪心真的太考验思维能力了,想到正确思路就能很简单。

你可能感兴趣的:(刷题,贪心算法,算法,leetcode)