数位DP(1)不含连续1的非负整数

最近在看数位dp,以为自己会了一些,刚看这道题目还是挺有思路的,但是做到后面又写不出来了,一看思路,直接寄几,思路有一点像,但又不想,先看题目:

这是 LeetCode 上的「600. 不含连续1的非负整数」,难度为「困难」

Tag : 「数位 DP」

给定一个正整数 n,找出小于或等于 n 的非负整数中,其二进制表示不包含 连续的1 的个数。

输入: 5

输出: 5

解释: 
下面是带有相应二进制表示的非负整数<= 5:
0 : 0
1 : 1
2 : 10
3 : 11
4 : 100
5 : 101
其中,只有整数3违反规则(有两个连续的1),其他5个满足规则。

我的思路:

首先把n转化为一个2进制的数字,然后这个二进制的数,可以分为两个部分,数位上小于这个数字的,和数位上等于这个数字的,例如:

101:

就可以划分为俩类:

第一类:101 100

第二类:0 1 10 

第二类好求,可以用dp求出来,第一类的话,就直接按高位慢慢枚举就可以求出来了,看代码:

class Solution(object):
    def findIntegers(self, n):
        if n == 1:
            return 2
        nums = [[j for j in range(35)] for i in range(2)]
        nums[0][1] = 1
        nums[1][1] = 1
        # print(range(35))
        for i in range(2,35):
            nums[0][i] = nums[0][i-1] + nums[1][i-1]
            nums[1][i] = nums[0][i-1]

        lala = []
        n1 = int(n)
        while n1>=1:
            lala.append(n1%2)
            n1 = int(n1/2)
        lala.reverse()

        number = 1
        for i in range(1,len(lala)):
            number = number + nums[1][i]
            # print(nums[1][i])
        befor = lala[0]
        if len(lala) > 1:
            number = number +1
        print(number)
        changdu = 0
        for i in lala[1:]:
            changdu = changdu +1
            if i == befor and i == 1 and len(lala) - changdu ==1:
                break;

            if i == 1:
                number = number + nums[0][len(lala) - changdu]
            if i == befor and i == 1:
                number = number -1
                break;
            if i == 1 and len(lala) - changdu !=1:
                number = number +1
            befor = i
            # print(i)
            # print(len(lala) - changdu)
        return number

但后面不好写了,就是我这样子考虑情况太多了,搞不懂。

官方的思路:

与我的大体一样,但它是列举最高位为1/0,长度为n的所有数的个数

例如: 长度为2,最高位为1的:1 0 10 

                           最高位为 0 的  0   1w

def findIntegers(n):
    nums = [[j for j in range(2)] for i in range(35)]
    nums[1][0] = 1
    nums[1][1] = 2
    for i in range(2,35):
        nums[i][1] = nums[i-1][1] + nums[i-1][0]
        nums[i][0] = nums[i-1][1]
    shu_wei = []
    n1 = int(n)
    while n1>=1:
        shu_wei.append(n1%2)
        n1 = int(n1/2)

    shu_wei.reverse()
    print(shu_wei)
    number = 0
    preserve = 0
    chang_du = 0
    for i in  shu_wei:
        if preserve ==1 and i == 1:
            break
        if i == 1:
            number = number + nums[len(shu_wei) - chang_du][0]
        # print(nums[len(shu_wei) - chang_du][1])
        preserve = i
        chang_du = chang_du+1
        if len(shu_wei) - chang_du == 0:
            number = number + 1
    # print(number)
    return  number

我和官方题解的只要区别: 我考虑的是最高为1,然后举例后位为0的,但官方为举例为后位为1的,就是这一个区别,导致我的代码极其麻烦。

感觉思路上大体都对了,后面还要再努力,应该就可以写出来了 

我根据官方题解,自己想了像,然后写出了这个低配版的解法。

这题的关键就在于: 数位上的数字为1的时候,要考虑nums[i][0],而不是nums[i][1],

代码如下:

class Solution(object):
    def findIntegers(self, n):
        if n ==1:
            return 2
        n1 = int(n)
        shu_wei = []
        while n1>=1:
            shu_wei.append(int(n1%2))
            n1 = int(n1/2)
        nums = [[j for j in range(2)] for i in range(35)]
        nums[1][0] = 1
        nums[1][1] = 2
        for i in range(2,35):
            nums[i][0] = nums[i-1][1]
            nums[i][1] = nums[i-1][0] + nums[i-1][1]
        number1 = nums[len(shu_wei) ][0]


        print(number1)
        number2 = 0
        shu_wei.reverse()
        print(shu_wei)
        preserve = 1
        for i in range(1 , len(shu_wei)):
            if shu_wei[i] == 1:
                number2 = number2 + nums[len(shu_wei) - i][0]
            if preserve == shu_wei[i] and shu_wei[i] ==1:
                break
            preserve = shu_wei[i]
            if i == len(shu_wei) -1:
                number2 = number2+1
        number = number1+number2
        return  number

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值