给定一个数组,它的第 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
在柠檬水摊上,每一杯柠檬水的售价为 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
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 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
机器人在一个无限大小的网格上行走,从点 (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