leetcode 专题:贪心算法 python 版(持续更新中)

贪心算法和动态规划

相同点:都是一种递推算法 即均由局部最优解来推导全局最优解

不同点:

贪心算法: 每一步的最优解一定包含上一步的最优解,上一步之前的最优解则不作保留,换句话说就是一开始就定好了最优策略

动态规划:记录之前的所有的局部最优解,可以列出递归公式。代码非常套路,一般都是设一个二维数组或者一维数组记录中间结果。

 

目录

122 买卖股票的最佳时机||

455 分发饼干

860 柠檬水找零

874 模拟行走机器人

944 删列造序列

1005 K次取反后最大化的数组和


目录

122 买卖股票的最佳时机||

455 分发饼干

860 柠檬水找零

874 模拟行走机器人


122 买卖股票的最佳时机||

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。

示例 2:

输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

思路:题目的意思其实是当天买入后当天还可以卖出,则算法可以直接简化为,只要今天比昨天大,就卖出。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        result = 0
        length = len(prices)
        for i in range(0, length-1):
            if prices[i+1] > prices[i]:
                result += prices[i+1]-prices[i]
        return result
            
            

 

455 分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

注意:

你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。

示例 1:

输入: [1,2,3], [1,1]

输出: 1

解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。

示例 2:

输入: [1,2], [1,2,3]

输出: 2

解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

思路:用尽量小的饼干去满足需求小的孩子,所以要先排序

class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        child = 0
        cookie = 0
        g.sort()
        s.sort()
        while child<len(g) and cookie<len(s):
            if g[child]<=s[cookie]:
                child+=1
            cookie+=1
        return child
        

 

 

860 柠檬水找零

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。

顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5美元。

注意,一开始你手头没有任何零钱。

如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

示例 1:

输入:[5,5,5,10,20]
输出:true
解释:
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 true。

示例 2:

输入:[5,5,10]
输出:true

示例 3:

输入:[10,10]
输出:false

示例 4:

输入:[5,5,10,10,20]
输出:false
解释:
前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零,所以答案是 false。

 

提示:

  • 0 <= bills.length <= 10000
  • bills[i] 不是 5 就是 10 或是 20 

 

思路:碰到20块先用一张10块一张5块的方式找零

class Solution:
    def lemonadeChange(self, bills: List[int]) -> bool:
        five = 0
        ten = 0
        for i in bills:
            if i==5:
                five+=1
            elif i==10:
                ten+=1
                if five>=1:
                    five-=1
                else:
                    return False
            elif i==20:
                if ten>=1 and five>=1:
                    ten-=1
                    five-=1
                elif five>=3:
                    five-=3
                else:
                    return False
        return True
            

 

 

874 模拟行走机器人

机器人在一个无限大小的网格上行走,从点 (0, 0) 处开始出发,面向北方。该机器人可以接收以下三种类型的命令:

  • -2:向左转 90 度
  • -1:向右转 90 度
  • 1 <= x <= 9:向前移动 x 个单位长度

在网格上有一些格子被视为障碍物。

第 i 个障碍物位于网格点  (obstacles[i][0], obstacles[i][1])

如果机器人试图走到障碍物上方,那么它将停留在障碍物的前一个网格方块上,但仍然可以继续该路线的其余部分。

返回从原点到机器人的最大欧式距离的平方

 

示例 1:

输入: commands = [4,-1,3], obstacles = []
输出: 25
解释: 机器人将会到达 (3, 4)

示例 2:

输入: commands = [4,-1,4,-2,4], obstacles = [[2,4]]
输出: 65
解释: 机器人在左转走到 (1, 8) 之前将被困在 (1, 4) 处

 

提示:

  1. 0 <= commands.length <= 10000
  2. 0 <= obstacles.length <= 10000
  3. -30000 <= obstacle[i][0] <= 30000
  4. -30000 <= obstacle[i][1] <= 30000
  5. 答案保证小于 2 ^ 31

 

思路:求过程中最大的欧氏距离

class Solution:
    def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int:
        direct = 0 #0:N, 1:E,2:S,3:W
        x = 0
        y = 0
        dx = [0,1,0,-1]
        dy = [1,0,-1,0]
        result =0
        for c in commands:
            if c==-1:
                direct= (direct+1)%4
            elif c==-2:
                direct= (direct+3)%4
            else:
                for i in range(c):
                    if not [x+dx[direct], y+dy[direct]] in obstacles:
                        x+=dx[direct]
                        y+=dy[direct]
                result = max(result, x*x+y*y)
        return result

 

944 删列造序列

给定由 N 个小写字母字符串组成的数组 A,其中每个字符串长度相等。

选取一个删除索引序列,对于 A 中的每个字符串,删除对应每个索引处的字符。 所余下的字符串行从上往下读形成列。

比如,有 A = ["abcdef", "uvwxyz"],删除索引序列 {0, 2, 3},删除后 A 为["bef", "vyz"], A 的列分别为["b","v"], ["e","y"], ["f","z"]。(形式上,第 n 列为 [A[0][n], A[1][n], ..., A[A.length-1][n]])。

假设,我们选择了一组删除索引 D,那么在执行删除操作之后,A 中所剩余的每一列都必须是 非降序 排列的,然后请你返回 D.length 的最小可能值。

示例 1:

输入:["cba", "daf", "ghi"]
输出:1
解释:
当选择 D = {1},删除后 A 的列为:["c","d","g"] 和 ["a","f","i"],均为非降序排列。
若选择 D = {},那么 A 的列 ["b","a","h"] 就不是非降序排列了。

示例 2:

输入:["a", "b"]
输出:0
解释:D = {}

示例 3:

输入:["zyx", "wvu", "tsr"]
输出:3
解释:D = {0, 1, 2}

提示:

  1. 1 <= A.length <= 100
  2. 1 <= A[i].length <= 1000

思路:从列到行循环,如果遇到降序的话,就记录这一列的下标。

class Solution:
    def minDeletionSize(self, A: List[str]) -> int:
        cancel = []
        n = len(A[0])
        for i in range(n):
            tmp = 'A[0][i]'
            for j in range(len(A)):
                if A[j][i]>=tmp:
                    tmp = A[j][i]
                else:
                    cancel.append(i)
                    break
        return len(cancel)
                    

 

1005 K次取反后最大化的数组和

给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次。(我们可以多次选择同一个索引 i。)

以这种方式修改数组后,返回数组可能的最大和。

 

示例 1:

输入:A = [4,2,3], K = 1
输出:5
解释:选择索引 (1,) ,然后 A 变为 [4,-2,3]。

示例 2:

输入:A = [3,-1,0,2], K = 3
输出:6
解释:选择索引 (1, 2, 2) ,然后 A 变为 [3,1,0,2]。

示例 3:

输入:A = [2,-3,-1,5,-4], K = 2
输出:13
解释:选择索引 (1, 4) ,然后 A 变为 [2,3,-1,5,4]。

 

提示:

  1. 1 <= A.length <= 10000
  2. 1 <= K <= 10000
  3. -100 <= A[i] <= 100

思路:每次最小的取反

class Solution:
    def largestSumAfterKNegations(self, A: List[int], K: int) -> int:
        for i in range(K):
            A.sort()
            A[0] = -A[0]
        
        return sum(A)

 

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值