目录
局部最优推出全局最优
解题步骤:
1. 将问题分成若干个子问题
2. 找出合适的贪心策略
3. 求解每一个子问题的最优解
4. 将局部最优解堆叠成全局最优解
455. 分发饼干
class Solution(object):
def findContentChildren(self, g, s):
"""
:type g: List[int]
:type s: List[int]
:rtype: int
"""
n_children, n_biscuits = len(g), len(s)
g.sort() # 小孩胃口值
s.sort() # 饼干尺寸值
i, j, count = 0, 0, 0
while i < n_children and j < n_biscuits:
if s[j] >= g[i]:
count += 1
i += 1
j += 1
else:
j += 1
return count
1005. k次取反后最大化的数组和
class Solution(object):
def largestSumAfterKNegations(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: int
"""
# 将nums按绝对值从大到小排列
nums = sorted(nums, key=abs, reverse=True)
for i in range(len(nums)):
# 从后向前遇到负数变成整数
if k > 0 and nums[i] < 0:
nums[i] *= -1
k -= 1
if k > 0:
nums[-1] *= (-1) ** k # 取A最后一个数只需要写-1
return sum(nums)
860. 柠檬水找零
收到20美元优先用10+5找零
import collections
class Solution(object):
def lemonadeChange(self, bills):
"""
:type bills: List[int]
:rtype: bool
"""
hashtable = collections.defaultdict(int)
i = 0
while i < len(bills):
hashtable[bills[i]] += 1
if bills[i] == 10:
hashtable[5] -= 1
elif bills[i] == 20:
if hashtable[10] > 0:
hashtable[10] -= 1
hashtable[5] -= 1
else:
hashtable[5] -= 3
for key in hashtable:
if hashtable[key] < 0:
return False
i += 1
return True
376. 摆动序列(序列问题)
# 找递增/递减的段数
class Solution(object):
def wiggleMaxLength(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
count = 1
flag = 0
if len(nums) == 1: return 1
for i in range(1, len(nums)):
if nums[i-1] < nums[i]:
if not flag or flag == -1:
flag = 1
count += 1
elif nums[i-1] > nums[i]:
if not flag or flag == 1:
flag = -1
count += 1
else:
continue
return count
738. 单调递增的数字(序列问题)
class Solution(object):
def monotoneIncreasingDigits(self, n):
"""
:type n: int
:rtype: int
"""
li = list(str(n))
n_len = len(li)
for i in range(n_len - 1, 0, -1):
if int(li[i]) < int(li[i - 1]):
# 当前位-1,后面的位全都变成9
li[i - 1] = str(int(li[i - 1]) - 1)
li[i:] = '9' * (n_len - i)
return int("".join(li))
122. 买卖股票的最佳时机ii(股票问题)
class Solution(object):
def maxProfit(self, prices):
"""
:type prices: List[int]
:rtype: int
"""
ans = 0
pre = prices[0]
for i in range(len(prices)):
if prices[i] > pre:
ans += prices[i] - pre
pre = prices[i]
return ans
714. 买卖股票的最佳时机含手续费(股票问题)
class Solution(object):
def maxProfit(self, prices, fee):
"""
:type prices: List[int]
:type fee: int
:rtype: int
"""
ans = 0
pre = prices[0]
for i in range(1, len(prices)):
# 当前价格小于最低点则更新最低点
if prices[i] < pre:
pre = prices[i]
# 当前价格高于最低点但是不赚钱
elif pre <= prices[i] <= pre + fee:
continue
# 当前价格卖出赚钱
else:
ans += prices[i] - pre - fee
# 如果下一个点的值更高,在这里就不卖了
pre = prices[i] - fee
return ans
135. 分发糖果(两个维度权衡问题)
两个维度权衡问题需要先确定一个维度,再考虑另一个维度,不然会顾此失彼。
class Solution(object):
def candy(self, ratings):
"""
:type ratings: List[int]
:rtype: int
"""
li = [0 for _ in range(len(ratings))]
li[0] = 1
# 比较右孩子是否比左孩子大
for i in range(len(li)-1):
if ratings[i] < ratings[i+1]:
li[i+1] = li[i] + 1
else:
li[i+1] = 1
# 比较左孩子是否比右孩子大
for j in range(len(li)-1, 0, -1):
if ratings[j-1] > ratings[j]:
li[j-1] = max(li[j] + 1, li[j-1])
return sum(li)
406. 根据身高重建队列(两个维度权衡问题)
# 将people按照lambda规则排序
# 1. peo[0]从大到小排序
# 2. peo[0]相等的情况下,peo[1]从小到大排序
# peo[i]是people中的每个元素
people.sort(key=lambda peo:(-peo[0], peo[1]))
class Solution(object):
def reconstructQueue(self, people):
"""
:type people: List[List[int]]
:rtype: List[List[int]]
"""
queue = []
people.sort(key=lambda peo:(-peo[0], peo[1]))
for val in people:
queue.insert(val[1], val)
return queue
55. 跳跃游戏(区间问题)
class Solution(object):
def canJump(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
n = len(nums)
maxrange = 0
for i in range(n):
if i <= maxrange:
maxrange = max(maxrange, i+nums[i])
if maxrange >= n-1:
return True
return False
45. 跳跃游戏ii(区间问题)
class Solution(object):
def jump(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)-1
i = 0
count = 0
while i <= n:
if i == n :
return count
if i + nums[i] < n:
maxrange = i + nums[i] + nums[i + nums[i]]
tmp = nums[i]
for step in range(1, nums[i]+1):
twostep = i + step + nums[i+step]
if twostep > maxrange:
maxrange = twostep
tmp = step
i += tmp
count += 1
else:
count += 1
return count
452. 用最少数量的箭引爆气球(区间问题)
计算重叠气球最小右边界进行分组,气球的组数即为需要弓箭数
class Solution(object):
def findMinArrowShots(self, points):
"""
:type points: List[List[int]]
:rtype: int
"""
points.sort(key=lambda poi: (poi[0], poi[1]))
ans = 1
i = 0
right = points[0][1]
while i < len(points):
if points[i][0] <= right:
right = min(right, points[i][1])
else:
right = points[i][1]
ans += 1
i += 1
return ans
435. 无重叠区间(区间问题)
只按照右边界排序即可(从左向右遍历,优先选右边界小的)
class Solution(object):
def eraseOverlapIntervals(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: int
"""
intervals.sort(key=lambda inter:inter[1])
i = 1
ans = 0
right = intervals[0][1]
while i < len(intervals):
# 当前区间与上一区间右边重叠
if intervals[i][0] < right:
ans += 1
else:
right = intervals[i][1]
i += 1
return ans
763. 划分字母区间(区间问题)
import collections
class Solution(object):
def partitionLabels(self, s):
"""
:type s: str
:rtype: List[int]
"""
ans = []
hashtable = collections.defaultdict(int)
# 统计每个字母最后出现的坐标
for i in range(len(s)):
hashtable[s[i]] = i
index = 0
pre = 0
right = hashtable[s[index]]
while index < len(s):
right = max(right, hashtable[s[index]])
if index == right:
ans.append(index+1-pre)
pre = index+1
index += 1
continue
right = max(right, hashtable[s[index]])
index += 1
return ans
56. 合并区间(区间问题)
class Solution(object):
def merge(self, intervals):
"""
:type intervals: List[List[int]]
:rtype: List[List[int]]
"""
intervals.sort(key=lambda x: x[0])
merged = []
for interval in intervals:
# 如果列表为空,或者当前区间与上一区间不重合,直接添加
if not merged or merged[-1][1] < interval[0]:
merged.append(interval)
else:
# 否则的话,我们就可以与上一区间进行合并
merged[-1][1] = max(merged[-1][1], interval[1])
return merged
53. 最大子序列和
# 动态规划
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
dp = [0 for _ in range(len(nums))]
dp[0] = nums[0]
for i in range(1, len(nums)):
dp[i] = max(dp[i-1] + nums[i], nums[i])
return max(dp)
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
result = -float('inf')
ans = 0
for i in range(len(nums)):
ans += nums[i]
if ans > result:
result = ans
if ans <= 0:
ans = 0
return result
134. 加油站
class Solution(object):
def canCompleteCircuit(self, gas, cost):
"""
:type gas: List[int]
:type cost: List[int]
:rtype: int
"""
rest = []
for i in range(len(gas)):
rest.append(gas[i]-cost[i])
cur_res = [rest[0]]
for i in range(1, len(rest)):
cur_res.append(cur_res[i-1]+rest[i])
min_res = min(cur_res)
if min_res > 0: return 0
start = len(rest)-1
while start > -1:
min_res += rest[start]
if min_res >= 0:
break
start -= 1
return start
968. 监控二叉树
局部最优:叶子节点的父节点上放摄像头
全局最优:用局部最优推出
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
# 不会用nonlocal用self.result代替了
class Solution(object):
def minCameraCover(self, root):
"""
:type root: TreeNode
:rtype: int
"""
# 0:无覆盖
# 1:有监控
# 2:有覆盖
self.result = 0
# 按后序遍历
def dfs(cur):
if not cur: return 2
left = dfs(cur.left)
right = dfs(cur.right)
if left == 2 and right == 2:
return 0
elif left == 0 or right == 0:
self.result += 1
return 1
elif left == 1 or right == 1:
return 2
if dfs(root)==0:
self.result += 1
return self.result