Leecode 53最大子序和 simple
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
if len(nums)==1: return nums[0]
max_sum = nums[0] #must两个,一个记录,一个遍历
cur_sum = max_sum
for i in range(1,len(nums)):
if (cur_sum+nums[i])>nums[i]:
cur_sum=cur_sum+nums[i]
else:
cur_sum=nums[i]
if cur_sum>max_sum: max_sum=cur_sum
return max_sum
Leecode 300最长上升子序列 median
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
if len(nums)<=1:return len(nums)
mem = [1 for _ in range(len(nums))] #设定每个点单独为一个子序列
for j in range(1,len(nums)):
for i in range(0,j):
if nums[i]<nums[j]:
mem[j]=max(mem[j],mem[i]+1) #!!!因可以discontinuous,故every new add j都需和之前all i单独相比;符合则加1;否则仍然为mem[j];也就是取max
return max(mem)
Leecode 322零钱兑换 median
贪心法:不一定能得到全局最优
DP:全局最优,自底向上解决problem
e.g:零钱1,3,4 6=4+1+1<贪心> 6=3+3< dp >
class Solution:
def coinChange(self, coins , amount ) -> int:
# 自底向上
# dp[i] 表示金额为i需要最少的硬币
# dp[i] = min(dp[i], dp[i - coins[j]]) j所有硬币
dp = [float('inf')]*(amount+1)
dp[0]=0 #amount=0,不需要硬币
for i in range(1,amount+1):
dp[i] = min(dp[i-c] if 0<=i-c else dp[i] for c in coins)+1
return dp[-1] if dp[-1]!=float('inf') else -1 # 易错点:dp[-1]!='inf' bug,因type(dp[-1])是float,type('inf')是str
0-1背包问题
同
大问题拆分成小问题,通过寻找大问题与小问题的递推关系,解决一个个小问题,最终达到解决原问题的效果
异
dp:记忆性 避免了重复计算;核心就在于填表,表填写完毕,最优解也就找到。
填表:(物品个数+1)x(len(weight_most + 1))
注意:dp填表要插入头一行(第0个物品,背包剩余容量all可能)
分治法:在子问题和子子问题等上被重复计算了很多次
0-1背包问题 参考python版
思想:第i个物品放or不放;
放:检测了第i个物品,剩余容积减weight[i],价值增加value[i]
不放:检测了第i个物品,价值不增加
放与不放中取价值max,的措施之一即可
weight = [2,3,4,5]#表示重量,各个物品
value = [3,4,5,6]#表示价值,各个物品
weight_most = 8 #最大容量
weight.insert(0, 0) # 前0件要用
value.insert(0, 0) # 前0件要用
import numpy as np
def bag_0_1(weight, value, weight_most): # return max value
num = len(weight)-1 #物品个数
bag = np.zeros([num + 1, weight_most + 1], dtype=np.int32) # python下标从零开始
for i in range(1, num + 1):
for j in range(weight_most,0,-1):
if weight[i] <= j:
bag[i][j] = max(bag[i - 1][j - weight[i]] + value[i], bag[i - 1][j])
else:
bag[i][j] = bag[i - 1][j]
return bag
result = bag_0_1(weight, value, weight_most) #整个表格
print(result[-1,-1]) #get最大价值
#find 路径----回溯
num = len(weight)-1 #物品个数
item=[0]*(num+1) #为路径表示分配内存
def find_item(i,j,item):
if i>=0:
if res[i,j]==res[i-1,j]:
item=find_item(i-1,j,item)
elif j-weight[i]>=0 and res[i,j]==res[i-1,j-weight[i]]+value[i]:
item[i]=1
item =find_item(i-1,j-weight[i],item)
return item
item = find_item(num,weight_most,item)
print(item)
%分割线----------------------------------------------------------------------------------------------------%
Leecode 416分割等和子集 median
时间复杂度:O(n*(target/2))
空间复杂度:O(n*(target/2))
#return是bool,不是‘False’–string
class Solution:
def canPartition(self, nums: List[int]) -> bool:
target = sum(nums)
if target % 2 != 0: return False
target //= 2 # 取和一半
n = len(nums)
dp = [[False] * (target + 1) for _ in range(n)]
# dp[0][0]=True
for j in range(target + 1): # 第一行 拎出来 打底
if j >= nums[0]:
dp[0][j] = True
break
for i in range(1, n):
for j in range(target + 1):
if nums[i] <= j:
dp[i][j] = dp[i - 1][j] or dp[i - 1][j - nums[i]]
else: #一定要有
dp[i][j] = dp[i - 1][j]
return dp[-1][-1]
时间复杂度:O(n*(target/2))
空间复杂度:O(target/2)
#参考,不强制学习
class Solution:
def canPartition(self, nums: List[int]) -> bool:
target = sum(nums)
if target % 2 != 0: return False
target //= 2 # 取和一半
n = len(nums)
dp = [[False] * (target + 1) for _ in range(n)]
# dp[0][0]=True
pre=[False]*(target + 1)
cur=[False]*(target + 1)
pre[0]=True
for j in range(target + 1): # 第一行 拎出来 打底
if j >= nums[0]:
pre[j]= True
break
#隐含pre=dp[i-1]行, cur=dp[i]行
for i in range(1, n):
for j in range(target + 1):
if nums[i] <= j:
cur[j]=pre[j] or pre[j-nums[i]]
else: #一定要有
cur[j] = pre[j]
return cur[-1]
Leecode 1049最后一块石头的重量 II median
#dp[i][j]代表选i个石头的最大重量j和
# 其中容量为sum/2, 即求最大的j<sum/2
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
total, n = sum(stones), len(stones)
dp = [[0]*(total//2+1) for _ in range(n)]
for j in range((total//2+1)):
if j>=stones[0]:
dp[0][j]=stones[0]
#break #break是bug一定不能有
for i in range(1, n):
for j in range(0, total//2+1):
if stones[i]<=j: # 这个代表选第i个, 然后再去比较选之后的大小
dp[i][j] = max(dp[i-1][j], dp[i-1][j-stones[i]]+stones[i])
else:
dp[i][j] = dp[i-1][j] # 这个代表不选第i个
return total-2*dp[-1][-1]
#方法二 不用单独拎出来第一行
class Solution:
def lastStoneWeightII(self, stones: List[int]) -> int:
total, l = sum(stones), len(stones)
dp = [[0]*(total//2+1) for _ in range(l+1)]
for i in range(1, l+1):
for j in range(1, total//2+1):
if stones[i-1]<=j: # 这个代表选第i个, 然后再去比较选之后的大小
dp[i][j] = max(dp[i-1][j], dp[i-1][j-stones[i-1]]+stones[i-1])
else: dp[i][j] = dp[i-1][j] # 这个代表不选第i个
return total-2*dp[-1][-1]
参考地址:https://leetcode-cn.com/problems/last-stone-weight-ii/solution/0-1bei-bao-by-yaosw/
Leecode 1046最后一块石头的重量 I simple
每一回合,从中选出两块 最重的 石头
#取负 建堆-弹出最大值-维护堆结构-弹出最大值--摩擦结果push回堆--循环
class Solution:
def lastStoneWeight(self, stones: List[int]) -> int:
import heapq ## heapq库是专门处理最小堆的库
stones_heap = [-i for i in stones] ## 用取负数的办法弯道处理最大堆问题
heapq.heapify(stones_heap) ## 把list最小推结构化;时间复杂度是O(n)
# 直接建堆
while len(stones_heap) > 1: ## 当至少还有2块石头的时候
a = heapq.heappop(stones_heap) #弹出max后,auto维护## 取出质量最大的石头(因为是负数,所以值是最小);时间复杂度是O(logn),因为取出后还要用logn的时间保持堆结构
b = heapq.heappop(stones_heap) ## 在剩下的石头里取出质量最大的石头;时间复杂度是O(logn)
if a < b: ## 如果第一块石头比第二块重,那么把摩擦剩下的小石头放进堆里
heapq.heappush(stones_heap, a - b) ## 如果两块石头一样重,就都没有了
if stones_heap:
res = -stones_heap[0] ## 如果剩下石头,那么返回值是其质量
else:
res = 0 ## 如果不剩下石头,那么返回值是0
return res