题目描述:
给定一个正整数 n
,请你统计在 [0, n]
范围的非负整数中,有多少个整数的二进制表示中不存在 连续的 1
输入输出实例:
思路:首先我们来说一个大家都能想得到的思路,遍历0~n,然后对这个数取二进制,找‘11’是否在其中,如果不在,我们count数量就加1,最后返回count。这个代码的时间复杂度是O(n*m)(n是数字个数,m是这个数字的二进制位数),这题不简单,不出意外是要超时的,代码如下:
def has_ones(num):
return '11' in bin(num)
class Solution:
def findIntegers(self, n: int) -> int:
#遍历0~n,转化为二进制,找二进制里面是否有两个连续的1,如果没有就count的值+1改变
count = 0
for i in range(n+1):
if not has_ones(i):
count += 1
return count
我们另寻他法, 我们要计算在 [0, n]
范围内不包含连续 1
的非负整数个数。我们可以将这个问题分为以下几个步骤:n转化为二进制观察它位数。如果一个数的末位是 0
,那么前面的部分可以是任意的有效数,如果末位是 1
,那么前面的部分必须以 0
结尾,以避免连续的 1。
我们可以利用类似于斐波那契数列的规律来计算有效数字的数量:如果我们有 k
位的数字,所有的有效数字数量由以下规则得出历史有效数的组合:fib[n] = fib[n-1] + fib[n-2]。我们需要一个count变量记录个数,一个prev_bit记录前一位是0还是1,然后当前位(我们从前往后)与1进行&运算,【比如n为5-即101,第一位为1,此时i为2,后面还有两位(01),而两位可以组成的符合题目要求的结果是3个,所以我们的count+=3,以此类推......所得的结果是正确的】,如果上一位为1,这一位也为1,我们返回count,否则吧记录前一位的变量prev_bit改为这一位‘1’;如果这位为0,prev_bit改为0,如果循环途中我们没有return,说明这个n本身也是满足条件的,我们count+=1,返回return。
class Solution:
def findIntegers(self, n: int) -> int:
#利用类似于斐波那契数列的规律来计算有效数字的数量
#fib[0] = 1 代表0位的时候只有0,fib[1]=2 一位数字有效的是0,1,fib[2] = 3 两位数字有效的是00,01,10......
fib = [1,2]
#假设最长的二进制位32位
for _ in range(2,32):
fib.append(fib[-1] + fib[-2])
count = 0
#记录前一位的状态
prev_bit = 0
#从高位往低位找
for i in range(31,-1,-1):
#当前位是否为1
if (n >> i) & 1 :
#当前为1,加入对应的组合
count += fib[i]
if prev_bit:
return count
prev_bit = 1
else:
prev_bit = 0
count += 1
return count