【Leetcode】top 100 贪心算法

基础知识补充

贪心算法:在对问题求解时,总是做到局部最优

局部最优并不总能获得整体最优解,但通常能获得近似最优解

题目
121 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

思路:如果day2价格高于day1价格,就假设day1买入day2卖出计算收益,如果day3价格高于day2价格,得假设day1买入day2不处理day3卖出...即需要记录前置的历史最低价,出现更低的价格时更新,而出现更高的价格时计算收益,出现次高价格的收益低于最高收益,不会被记录;

python 复制代码
class Solution(object):
    def maxProfit(self, prices):
        """
        :type prices: List[int]
        :rtype: int
        """
        buy, sell = prices[0], 0
        for val in prices:
            if val > buy: sell = max(val-buy, sell)
            else: buy = val
        return sell
55 跳跃游戏

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false

思路:当前坐标元素大于数组长度时,一定能到最后一个下标;否则每一步都跳满,再次判断;若当前坐标元素为0,就选择回退一步,再跳满,否则回退两步再跳满...回退到开头仍无法跳过该处0,则永远不可能到达最后一个下标;

python 复制代码
class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        i, n = 0, len(nums)-1
        while i>=0 and i<n:
            if nums[i]: i = i+nums[i]
            else:
                idx = i
                while idx >= 0:
                    if idx+nums[idx]>i: break
                    idx -= 1
                i = idx
        return i>=0

更简洁思路:一次遍历每个元素(除最后),用变量记录当前能到达的最远位置,下标大于最远距离时遍历结束,当遍历结束时判断最远位置是否到达最后一个坐标即可;

python 复制代码
class Solution(object):
    def canJump(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        distance, n = 0, len(nums)-1
        for i, val in enumerate(nums):
            if i > distance: break
            distance = max(distance, i+val)
        
        return distance>=n
45 跳跃游戏II

给定一个长度为 n0 索引 整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在 下标i 处,你可以跳转到任意 下标i+j 处:

  • 0 <= j <= nums[i]
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

思路:动态规划

dp[i] 表示到达下标 i 的最小跳跃数

转移状态:dp[i] = min(dp[i], dp[k]+1) k+nums[k]>=i

初始状态:dp[0] = 0

python 复制代码
class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        dp = [float('inf')]*n
        dp[0] = 0
        for i in range(n):
            for k in range(i):
                if k+nums[k] >= i:
                    dp[i] = min(dp[i], dp[k]+1)
        return dp[-1]
# 执行用时过长

动态规划的优化

dp[i] 是一个非降序数组,所以在找dp[k]时只要找到第一个符合条件的k即可;

而且对于递增的 i,k也是递增的,不需要回退到0再遍历;

python 复制代码
class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        dp = [float('inf')]*n
        dp[0] = 0
        k = 0
        for i in range(1, n):
            while k+nums[k] < i:
                k+=1
            dp[i] = dp[k]+1    # 由于会进行这个+1操作,要么dp[0]=-1,要么遍历跳过nums[0]
        return dp[-1]

更简洁思路:每次跳跃都要跳到最远

以 [3,1,4,2,8] 为例:3最远可以跳到2,在3-2的范围里搜索下一次能跳跃的最远值;

仍依次遍历数组(除最后),当运动到前一次跳跃的最远值时(边界2),将跳跃次数+1同时更新边界;

python 复制代码
class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        n = len(nums)
        distance, cnt, end = 0, 0, 0
        for i in range(n-1):
            distance = max(distance, i+nums[i])
            if i == end:
                cnt+=1
                end = distance
        return cnt
763 划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。返回一个表示每个字符串片段的长度的列表。

思路片段数尽可能多等于每个片段尽可能短;

对于第一个字符(左界),需要将其最远的同字符(右界)与其共同在一个片段中,然后界内判断还需不需要纳入其他字符的同字符(改变右界)当左右界重合时得到了符合要求的一个最短片段;

因为需要查找同字符的最远位置,事先构造了一个哈希表储存字符和其对应下标;

优化:只保存同字符的最远坐标,可以节省哈希表的空间;

python 复制代码
class Solution(object):
    def partitionLabels(self, s):
        """
        :type s: str
        :rtype: List[int]
        """
        # tmp = []
        tmp = defaultdict(list)

        for i in range(len(s)):    
            # tmp[s[i]] = i
            tmp[s[i]].append(i)

        
        left, right, out = 0,0,[]
        for i in range(len(s)):
            right = max(right, max(tmp[s[i]]))

            if i == right: 
                out.append(right-left+1)
                left, right = i+1, 0
        return out
相关推荐
猿究院--王升3 小时前
jvm三色标记
java·jvm·算法
一车小面包3 小时前
逻辑回归 从0到1
算法·机器学习·逻辑回归
tt5555555555554 小时前
字符串与算法题详解:最长回文子串、IP 地址转换、字符串排序、蛇形矩阵与字符串加密
c++·算法·矩阵
元亓亓亓5 小时前
LeetCode热题100--101. 对称二叉树--简单
算法·leetcode·职场和发展
不会学习?6 小时前
算法03 归并分治
算法
NuyoahC6 小时前
笔试——Day43
c++·算法·笔试
2301_821919926 小时前
决策树8.19
算法·决策树·机器学习
秋难降7 小时前
别再用暴力排序了!大小顶堆让「取极值」效率飙升至 O (log n)
python·算法·排序算法
学行库小秘7 小时前
基于门控循环单元的数据回归预测 GRU
人工智能·深度学习·神经网络·算法·回归·gru
_meow_8 小时前
数学建模 15 逻辑回归与随机森林
算法·数学建模·逻辑回归