【leetcode系列】小菜鸡的leetcode第16题:动态规划入门(3)打家劫舍/打家劫舍2/打家劫舍变身进阶版:删除并获得点数

【动态规划问题】:
主要是找到第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))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值