【动态规划问题】:
主要是找到第i个状态时候的通解,并且改通解可以通过边界条件(初始值)得以推出
有0存在并不影响结果:因为0值的加和等于前面的dp,会使得计算结果倒推时自动选择前面有数值的索引处进行比较
图解版如下:
1.打家劫舍初级版(从头到尾):
class Solution:
def rob(self, nums: List[int]) -> int:
n=len(nums)
if n==0:
return 0
if n==1:
return nums[0]
if n==2:
return max(nums[0],nums[1])
F=[0]*n
#一家
F[0]=nums[0]
#二家
F[1]=max(nums[0],nums[1])
#如果n=2,for循环不执行
#三家起
for i in range(2,n):
F[i]=max(F[i-1],F[i-2]+nums[i])
return F[n-1]
2.打家劫舍进阶版(环状,首尾相邻):
class Solution:
#def slide(self,start:int,end:int)->list[int]:
# F=[0]*nums
def rob(self, nums: List[int]) -> int:
n=len(nums)
if n==0:
return 0
if n==1:
return nums[0]
if n==2:
return max(nums[0],nums[1])
#第一种情况,从第1家开始,到n-1家
F1=[0]*n
#一家n=1
F1[0]=nums[0]
#两家n=2
F1[1]=max(nums[0],nums[1])
#n>=3
for i in range(2,n-1):
F1[i]=max(F1[i-2]+nums[i],F1[i-1])
#第二种情况,从第2家开始,偷到第n家
F2=[0]*n
#n=1
F2[1]=nums[1]
#n=2
F2[2]=max(nums[1],nums[2])
#n=3
for j in range(3,n):
F2[j]=max(F2[j-2]+nums[j],F2[j-1])
#比较两种情况的最大值,保留
return max(F1[n-2],F2[n-1])
3.打家劫舍变身版:删除并获得点数:
正解code,效率还是蛮高的:
class Solution:
def deleteAndEarn(self, nums: List[int]) -> int:
maxindex=max(nums)
#索引有0,因此+1,否则索引范围为0~maxindex-1
counts=[0]*(maxindex+1)
for num in nums:
#快速计数法,每次循环到num指针时数值+1
counts[num]+=1
#count即为排序好的(根据索引顺序对数值排序)计数重复数值出现次数的最终数列
#打家劫舍经典解法
n=len(counts)
#F=[0]*n
#F[0]=0*counts[0]
#F[1]=max(F[0],1*counts[1])
#内存优化,动态赋值
a=0
b=0*counts[0]
#c=max(b,1*counts[1])
c=1*counts[1]
for i in range(2,n):
#不能选取nums中相邻数值,即不能选择counts中相邻索引
#F[i]=max(F[i-2]+i*counts[i],F[i-1])
#c=max(a,b)
#a=a+i*counts[i]
#b=
a,b=b+i*counts[i],c
c=max(a,b)
#return max(F)
return c
#这道题开始理解错误了,不得不说,读懂题比什么都重要啊喂- -
#下面注释掉的一种解法就是理解为,每次只能随机选择一个种子点,且一次运行只有一次种子点的选取。。
#这愚蠢的理解,我还做了两种解法,一种轮转数组遍历列表;一种用字典(不得不说字典真快真香)
#大家就当作为另一种题目,看看代码玩玩吧、、
#题目1:
#给你一个整数数组nums,你可以对它进行一些操作。
#选择任意一个nums[i],删除它并获得nums[i]的点数。之后,删除所有等于nums[i] - 1 和 nums[i] + 1的元素。
#开始你拥有 0 个点数。返回通过该操作获得的最大点数。
#法1:字典解法,不存在顺序
class Solution:
def deleteAndEarn(self, nums) -> int:
n=len(nums)
keys=list(range(n))
d=dict(zip(keys,nums))
#初始化count值
count=0
sums=0
while count < n:
#print(count)
d = dict(list(zip(keys, nums)))
for i in range(n):
# filter(lambda i: d[i] == nums[count] + 1 or d[i] == nums[count] - 1,d)
if d[i] == nums[count] + 1 or d[i] == nums[count] - 1:
# print (d[i])
del (d[i])
# replce()
# t=sum(d.values())
# print(t)
sums = max(sums, sum(d.values()))
#print(sums)
count += 1
#print(d)
return sums
'''
#法2;轮转数组思想,每次选取不同的种子点
class Solution:
def deleteAndEarn(self, nums):
n = len(nums)
if n == 0:
return 0
if n == 1:
return nums[0]
# 用切片形式进行数据深拷贝而不是a=nums,防止nums变动时,a也发生同样变化
a = nums[:]
#i = 1
add = 0
#n = len(nums)
for i in range(n):
for j in range(n):
if abs(a[j] - a[i]) == 1:
# print(nums[j])
a[j] = 0
# print(copy)
add = max(sum(a), add)
#轮转数组,用切片方式
#nums[:] = nums[i:] + nums[:i]
a = nums[:]
# print(a)
#i += 1
return add
'''
if __name__=='__main__':
nums=[2,2,3,3,3,4]
#nums=[1,1,1,2,4,5,5,5,6]
a=Solution()
print(a.deleteAndEarn(nums))