不含连续1的非负整数
不含连续1的非负整数
题目描述
给定一个正整数 n,找出小于或等于 n 的非负整数中,其二进制表示不包含 连续的1 的个数。
输入输出样例
输入: 5
输出: 5
解释:
下面是带有相应二进制表示的非负整数<= 5:
0 : 0
1 : 1
2 : 10
3 : 11
4 : 100
5 : 101
其中,只有整数3违反规则(有两个连续的1),其他5个满足规则。
题目分析
- 这是一道数位dp问题
- 设置dp[i][0]和dp[i][1],前者表示i位数最高位为0的所有可能的所有非负整数个数,后者表示i位数最高位为1的所有可能的所有非负整数个数
- 然后把输入的数n拆分成二进制的形式,从最高位开始判断。
- 对于第i位,如果为1,那么这一位为0时的所有数都应该加到结果中,即res+=dp[i][0]。比如n=5(二进制:101)时,最高位为1,那么对于最高位为0 的所有数即3、2、1、0,应该都在里面。如果为0,那么直接跳过,因为这一位为零时,你已经在算最高位的时候算过了。比如阅读到5的第二位,发现是0,那么就应该直接跳过,不然你就会把1、0这两个数有算一遍。
- 在每次进入下一次循环的时候,你需要记录下这个数作为下一次循环的数的前趋(即该位数的上一位),如果发现前趋=当前位=1,那么直接跳出循环,因为已经有连续的1了。
- 另外,上面的算法只能算出小于n的数,如果能循环到最后一位即i==0时,就说明n这个数也不含连续1,那么需要将res再加上1,因为你没有把n算上,你的结果是0 ~ n-1的不含连续1的个数。
题目代码
class Solution:
def findIntegers(self, n: int) -> int:
dp=[[0]*2 for _ in range(32)]
dp[0][0]=1
biary=[]
res=0
for i in range(1,32):
#初始化dp数组
dp[i][1]=dp[i-1][0]
dp[i][0]=dp[i-1][0]+dp[i-1][1]
while n!=0:
#转换成二进制格式,biary[0]是最低位
biary.append(n%2)
n=int(n/2)
i=len(biary)-1
pre=0
while i >=0:
if biary[i]==1:
res+=dp[i+1][0]
if pre==biary[i]:
break
pre=biary[i]
if i==0: res+=1 #如果i到0,就说明n不含连续1,要把自己算上去
i-=1
return res

浙公网安备 33010602011771号