区间内所有整数包含的某数字的个数

您所在的位置:网站首页 含8的数字的个数是多少 区间内所有整数包含的某数字的个数

区间内所有整数包含的某数字的个数

2024-07-16 12:11:22| 来源: 网络整理| 查看: 265

前言

最近连着两次遇到了该类问题,这类问题看上去挺简单,但是想要非暴力破解还是挺复杂的,我每次都是做2个多小时才能做出来,实际上这早就超时了。 我们只能做出已经学过的题目,而对于没有思路的这类题目,几乎不可能在半小时内做完。所以这里总结下,可能以后还会遇到。

题目描述

统计从a到b(包含a,b),区间所有二进制数中1的个数。比如,从1到3的全部二进制包括1(1B),2(10B),3(11B),所有1的个数就是1+1+2=4.a,b的取值范围1E9.

题目分析

本质上是数[0,n)所有整数上二进制中1的个数cnt(n),题目所求cnt_between(a,b)=cnt(b)-cnt(a)+cnt_one_num(b),其中cnt_one_num(b)表示b二进制表示时1的个数。 其中cnt(n)怎么求呢?这个得拆解,现举例说明,求[0,1011B)区间整数所有1的个数。当然暴力的方法虽然思路简单,但是复杂度太高,不合要求。先拆解成子问题,按数位拆分,最高位1表示1000B,那么子问题可以是[0,1000B),同理也会拆分为其余的[1000B,1010B),[1010B,1011),这样就可以了。 那么[0,1000B)如何计算呢? 这类问题可以概括为[0,1),[0,10B),[0,100B),[0,1000B)等一系列问题。然后由简单到复杂去求解即可得到通用的思路。 定义函数cnt_bit(b)来计算 [ 0 , 2 b ) [0,2^b ) [0,2b) 所有整数上二进制中1的个数,容易得知cnt_bit(0)=0,cnt_bit(1)=1,然后cnt_bit(2)表示[00,11B]中1的个数,它分为高位和低位分别来统计。低位有2cnt_bit(b-1)个1,因为高位有2种情况(0和1),所以是2cnt_bit(b-1),b=2就是有2个,即01B和11B这里的低位都是1;高位有 1 ∗ ( 2 b − 1 ) 1*(2^{b-1} ) 1∗(2b−1)个,也就是说,高位为1的时候,有 2 b − 1 2^{b-1} 2b−1个数,在b=2的时候,就是有2个即10B和11B,这里的高位都是1.所以总结会有 c n t _ b i t ( b ) = { 0 i f b = 0 1 i f b = 1 2 × c n t _ b i t ( b − 1 ) + 2 b − 1 i f b > 1 cnt\_bit(b)=\begin{cases} 0 & if\quad b=0 \\ 1 & if\quad b=1 \\ 2 \times cnt\_bit(b-1)+2^{b-1} & if\quad b>1 \end{cases} cnt_bit(b)=⎩ ⎨ ⎧​012×cnt_bit(b−1)+2b−1​ifb=0ifb=1ifb>1​ 现在来求cnt(n),回到原来的问题,求[0,1011B)区间整数所有1的个数,子问题是[0,1000B),[1000B,1010B),[1010B,1011)中1的个数,[0,1000B)是cnt_bit(3)个1.[1000B,1010B)要聚焦到第1位的1,它前面有1个1,这个1会出现[00,10B)次,也就是 2 1 2^1 21次;其余部分有cnt_bit(1)个1,加起来即可。[1010B,1011)这部分同理,左边有 2 × 2 0 = 2 2\times2^0=2 2×20=2个,右边有cnt_bit(0)=0个,加起来就是2个也就是1010B左侧有2个。 整理下思路,我们需要从左往右数(高位到低位),需要知道左侧有多少个1,这个变量用left_cnt表示,这时来尝试解一下。

def cnt(n): """ :return 数[0,n)所有整数上二进制中1的个数 :param n:区间上限,开区间 """ bits = [] #存放n的二进制形式 while n>=2: bits += [n%2] n//=2 bits += [n%2] left_cnt = 0 # 数位左侧1的个数 ans = 0 #返回值 for i,n in enumerate(bits[::-1]):# 从高位到低位遍历 b = len(bits)-i-1# 数位,比如n=1011B,i=0时,b=3 if n ==1: ans +=left_cnt * 2**b+cnt_bit(b) left_cnt+=1 return ans

接下来处理下边界值,cnt_one_num(n),这个函数用来数数字n的二进制形式中1的个数,由于这里只有1个数字,直接数即可。

def cnt_one_num(n): """ :param n: 输入数字 :return: n二进制形式中有多少个1 """ ans = 0 #返回值 while n>=2: if n%2 == 1: ans+=1 n//=2 if n % 2 == 1: ans += 1 return ans

基本思路就是这样。 完整代码参考如下:

def cnt_between(a,b): """ :return: [a,b]区间所有数二进制形式中1的个数 """ return cnt(b)-cnt(a)+cnt_one_num(b) def cnt(n): """ :return 数[0,n)所有整数上二进制中1的个数 :param n:区间上限,开区间 """ bits = [] #存放n的二进制形式 while n>0: bits += [n%2] n//=2 left_cnt = 0 # 数位左侧1的个数 ans = 0 #返回值 for i,n in enumerate(bits[::-1]):# 从高位到低位遍历 b = len(bits)-i-1# 数位,比如n=1011B,i=0时,b=3 if n ==1: ans +=left_cnt * 2**b+cnt_bit(b) left_cnt+=1 return ans def cnt_bit(b): """ :return 计算[0,2^b)所有整数上二进制中1的个数 :param b: b=0时,[0,1);b=1时,[0,2)... """ if b==0: ans= 0 elif b==1: ans= 1 else: ans = 2 * cnt_bit(b - 1) + 2 ** (b - 1) # print(b,ans) return ans def cnt_one_num(n): """ :param n: 输入数字 :return: n二进制形式中有多少个1 """ ans = 0 #返回值 while n>0: if n%2 == 1: ans+=1 n//=2 return ans def check_between(a,b): """ :return: 暴力法计算[a,b]所有整数二进制形式中1的个数 """ ans = 0 for n in range(a,b+1): ans += cnt_one_num(n) return ans if __name__ == "__main__": a = 0 b = 11 ans1, ans2 =cnt_between(a,b),check_between(a,b) print("successed" if ans1 == ans2 else "failed",ans1,ans2)


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭