Leetcode-贪心

122. 买卖股票的最佳时机ii  https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/

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

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

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

解:

dfs,找到所有可能买入卖出情况,O(2n),搜索的限制条件太少,递归层数太多,肯定超时。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        def dfs(prices, s):
            if s > len(prices):
                return 0
            res = 0
            for start in range(s, len(prices)):
                max_profit = 0
                for end in range(start+1, len(prices)):
                    if prices[start] < prices[end]:  # 如果当前的卖出高于买入,就卖出,从当前end卖出的整体收益等于这次卖出的收益+从下一天开始继续操作的收益
                        profit = prices[end] - prices[start] + dfs(prices, end+1)
                        if profit > max_profit:
                            max_profit = profit  # 记录从start买入,不同点卖出的最大收益
                if max_profit > res:
                    res = max_profit  # 记录从不同点买入的最大收益
            return res
        return dfs(prices, 0)

  

贪心,因为可以多次买入卖出,找出那些共同使得利润最大化的买入及卖出价格即可。只要第二天股价涨了,就在当天买入第二天卖掉。O(N)

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

  

动态规划,只要第二天涨了,卖了就赚了,否则就持有。记录每一天的状态记录最大利润,状态转移方程为:dp[i] = dp[i-1]  if prices[i] <= prices[i-1] else dp[i-1] + prices[i] -prices[i-1],遍历一次即可,O(n)

    def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0
        n = len(prices)
        dp = [0]*n
        for i in range(1, n):
            if prices[i] > prices[i-1]:
                dp[i] = dp[i-1] + prices[i] -prices[i-1]
            else:
                dp[i] = dp[i-1]
        return max(dp)

  

但其实不需要单独开一个数组,因为只要所有状态中最大的即可。写出来发现跟贪心就一样了。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0
        n = len(prices)
        res = 0
        for i in range(1, n):
            if prices[i] > prices[i-1]:
                res = res + prices[i] - prices[i-1]
            else:
                continue
        return res

  

860.柠檬水找零 https://leetcode-cn.com/problems/lemonade-change/

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

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

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

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

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

提示:

0 <= bills.length <= 10000

bills[i] 不是 5 就是 10 或是 20 

解:

模拟过程,贪心策略在于要尽可能多留5元在手里

class Solution:
    def lemonadeChange(self, bills: List[int]) -> bool:
        if not bills:
            return True
        
        five, ten = 0, 0
        for bill in bills:
            if bill == 5:  # 如果付5元,不用管
                five += 1
            elif bill == 10:  # 如果付10元,手里必须要有5元可以找
                if not five:
                    return False
                ten += 1
                five -= 1
            elif bill == 20: # 如果付20元,手里必须要有3张5元或1张5元1张10元可以找,贪心策略在于要尽可能的多留5元在手上
                if ten and five:  # 先走5+10的方案
                    ten -= 1
                    five -= 1
                elif five >= 3:
                    five -= 3
                else:
                    return False
        return True

  

455. 分发饼干 https://leetcode-cn.com/problems/assign-cookies/

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

注意:

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

解:

贪心,先把g和s都sort一下。对g和s分别维护一个索引。如果当前sj可以满足gi,res、i、j都加1;否则的话饼干的索引+1(换个更大的饼干)。如果最大的sj都比gi小,说明后面的gi已经不可能被满足,直接返回结果。

class Solution:
    def findContentChildren(self, g: List[int], s: List[int]) -> int:
        if not g or not s:
            return 0
        g.sort()
        s.sort()
        i, j, res = 0, 0, 0
        while i < len(g) and j < len(s):
            if s[-1] < g[i]:
                return res
            if s[j] >= g[i]:
                res += 1
                i += 1
                j += 1
            else:
                j += 1
        return res

  

  

874. 模拟行走机器人 https://leetcode-cn.com/problems/walking-robot-simulation/

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

-2:向左转 90 度
-1:向右转 90 度
1 <= x <= 9:向前移动 x 个单位长度
在网格上有一些格子被视为障碍物。

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

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

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

提示:

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

解:

按照题目要求模拟,把方向表示和step的索引结合起来用,注意障碍的位置用hashset存一下,每次查询就O(1)。

class Solution:
    def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int:
        if not commands:
            return 0
        direct = 0  # 初始面向北方 1: 东;2:南;3:西
        res = 0
        loc = (0, 0)  # 初始位于原点,direct = 0, y+step; 1,x+step; 2, y-step; 3, x-step 
        step_x = (0, 1, 0, -1)
        step_y = (1, 0, -1, 0)
        
        obstacles = set(map(tuple, obstacles))
        
        for v in commands:
            if v == -1:  # 向右转90度
                direct += 1
                direct %= 4
                
            elif v == -2:  # 向左转90度
                direct += 3  # -1+4
                direct %= 4

            else:  # 前进
                while v:
                    if (loc[0]+step_x[direct], loc[1]+step_y[direct]) in obstacles:
                        break
                    loc = (loc[0]+step_x[direct], loc[1]+step_y[direct])
                    res = max(res, loc[0]**2 + loc[1]**2)
                    v -= 1
        return res

  

 

posted @ 2019-08-15 17:26  王朝君BITer  阅读(223)  评论(0编辑  收藏  举报