最近在看数位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