文章目录
- 前言
- 题目描述
- 输入描述
- 输出描述
- 示例 1
- 示例2
- 题目解析
- 参考代码
前言
《华为机试真题详解 Python实现》专栏含牛客网华为专栏、华为面经试题、华为OD机试真题。
如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议!
本文解法非最优解(即非性能最优),不能保证通过率。
特别提醒!!!!
注意1:机试为ACM 模式
你的代码需要处理输入输出,input
接收输入、注意2:机试按通过率记分
复杂题目可以考虑暴力破解,再逐步优化,不是运行超时就无法得分,如下,提交结果运行超时,但用例通过率>92.31% , 如果是100分的题目,可以得92.3分。
题目描述
小明在学习二进制时,发现了一类不含 101的数,也就是:
将数字用二进制表示,不能出现 101 。
现在给定一个整数区间 [l,r] ,请问这个区间包含了多少个不含 101 的数?
输入描述
输入的唯一一行包含两个正整数 l, r( 1 ≤ l ≤ r ≤ 10^9)。
输出描述
输出的唯一一行包含一个整数,表示在 [l,r] 区间内一共有几个不含 101 的数。
示例 1
输入:
1 10
输出:
8
示例说明:
区间 [1,10] 内, 5 的二进制表示为 101 ,10的二进制表示为 1010 ,因此区间 [ 1 , 10 ] 内有 10−2=8 个不含 101的数。
示例2
输入:
10 20
输出:
7
示例说明:
区间 [10,20] 内,满足条件的数字有 [12,14,15,16,17,18,19] 因此答案为 7。
题目解析
有两个思路:
第一种是对区间中的每个数值求二进制然后判断其中是否包含101,如果不包含记数+1;
第二种是求最值的二进制,然后移动101的位置,求可能的组合个数,总数减去包含的个数就是带输出个数;
从输入的数值范围可以看出,如果使用第一种方法肯定是会超时的,感兴趣的同学可以自行实现,在评论区分享。
示例2的分析:
10对应的二进制 01010
20对应的二进制 10100
一共5位数,
从最右侧开始找可能的组合 第一种00101小于01010跳过;
左移一位第二种01010等于01010,替换第一位数和第五位数找可能,11010、11011、01011,前两个超出范围也不计算个数;(这里我们可以只考虑对101右则的位置求组合数)
再左移一位第二种10100等于10100,替换第四位数和第五位数找可能,10101,10110,10111,都超出范围也不计算个数;
区间内满足条件的二进制有 01010、01011、10100,一共三个,10-3=7,输出7;
参考代码
def get_permutations(data=None):
if not data:
return ["0", "1"]
tmp = []
for c in data:
tmp.append(c+"0")
tmp.append(c+"1")
return tmp
while 1:
try:
_mini, _maxi = map(int, input().split())
_minb = bin(_mini)[2:]
_maxb = bin(_maxi)[2:]
lens = max(len(_minb), len(_maxb))
sign = "101"
# 最大值小于5的情况
if lens < len(sign):
print(_maxi-_mini)
break
set101 = set()
permutations = None
# 101可移动的次数
for i in range(lens-len(sign)):
permutations = get_permutations(permutations)
for c in permutations:
if int(sign+c, 2) > _maxi:
break
set101.add(sign+c)
print(_maxi-_mini-len(set101))
except Exception as e:
break