您的位置:首页 > 编程语言

编程之美--高效率算出1的数目之扩展问题

2012-12-26 11:19 246 查看
问题:给定一个十进制数N,写下从1开始,到N的所有二进制数,然后数一下其中出现的所有“1”的个数。

问题分析:

十进制二进制最右边1的个数总和倒数第二1的个数总和 倒数第三1的个数总和倒数第四1的个数总和倒数第五1的个数总和十进制二进制最右边1的个数总和倒数第二1的个数总和倒数第三1的个数总和倒数第四1的个数总和倒数第五1的个数总和
00000000000130110176660
10000110000140111077770
20001011000150111188880
30001122000161000088881
40010022100171000198882
50010132200181001099883
6001103330019100111010884
7001114440020101001010985
80100044410211010111101086
90100154420221011011111187
100101055430231011112121288
110101166440241100012121299
12011006655025110011312121010
首先我们看2,、4、8、16四个数,2的二进制数总共有2个1,4的有5个,8的有13个,16有33个。而且他们都有一定的规律。比如16是2的4次方,二进制数是10000,在最右边1的个数和倒数第二、第三、第四都是8(即4个8),最高位是1;8是2的3次方,二进制数是01000,在最右边1的个数和倒数第二、第三都是4(3个4),倒数第四个是1;以此类推4和2,那么我们可以看出符合这样的公式:

0~2^n的所有二进制数1的总和sum=2^(n-1)*n+1 其中2^n表示2的n次方

现在我们观察0~24的数的二进制的最右边位的1的个数总和,0,1,1,2,2,3,3,4,4,5,5,6,6...,可以得出这样的公式:

0~n的所有二进制数最右边位的1的个数总和sum:当n%2=0时,sum=n/2; 否则sum=n/2+1

观察倒数第二位1的总和。0~1是0,其他的都是一个常数带上三个相同的常数;比如1,2,2,2,;3,4,4,4;5,6,6,6.... 那么设他们的规律是1+3为一组。

我们设sequenceLength=1,repeatLength=3;

这样子我们可以计算出18的二进制数的倒数第二位的1的总和为:看上面表格知道从0开始,那么18就是第19位,看倒数第二1的个数这一列前面是两个0,推出(18+1-2)/(1+3)取整为4,就是说有4组,每组的值其实是两个,那么sum=4*2=8,而(18+1-2)%(1+3)=1;所以sum=4*2+1=9;

观察倒数第三位1的总和。0~3是0,其他的都是三个常数带上五个相同的常数;比如1,2,3,4,4,4,4,4;5,6,7,8,8,8,8,8;9,10,11,12,12,12,12,12.... 那么设他们的规律是3+5为一组。

这样子我们可以计算出18的二进制数的倒数第三位的1的总和为:看上面表格知道从0开始,那么18就是第19位,看倒数第三1的个数这一列前面是四个0,推出(18+1-4)/(3+5)取整为1,就是说有1组,每组的值其实是4个,那么sum=1*4=4,而(18+1-4)%(3+5)=7;就是说18这个数为一组还多七个,由3+5为一组可知,多出来的七个的前三个的值是连续的,后面四个是一样的。那么这多出来的七个数其实就是3+1个值,推出sum=1*4+(3+1)=8。

观察倒数第四位1的总和。0~7是0,其他的都是三个常数带上五个相同的常数;比如1,2,3,4,5,6,7,8,8,8,8,8,8,8,8,8;.... 那么设他们的规律是7+9为一组

这样子我们可以计算出18的二进制数的倒数第四位的1的总和为:看上面表格知道从0开始,那么18就是第19位,看倒数第四1的个数这一列前面是八个0,推出(18+1-8)/(7+9)取整为0,就是说有0组,每组的值其实是8个,那么sum=0*8=0,而(18+1-8)%(7+9)=11;就是说18这个数为零组还多十一个,由7+9为一组可知,多出来的十一个的前七个的值是连续的,后面九个是一样的。那么这多出来的十一个数其实就是7+1个值,推出sum=0*8+(7+1)=8。

倒数第二位、倒数第三位。。。倒数第N位的组的规律。

1+3;3+5;7+9 可知(1+2^1)+(3+2^1)=3+5; (3+2^2)+(5+2^2)=7+9......

和面组是前面组的2的幂次方。倒数第二位是2的一次方,倒数第三位是2的两次方...以此类推。

代码分析:

View Code

class Program
{
static void Main(string[] args)
{
NumberOfOne numberOfOne = new NumberOfOne();
while (true)
{
int number = int.Parse(Console.ReadLine());
numberOfOne.BinaryCount(number);
Console.WriteLine("0~{0}的所有二进制数的1的总和为:{1}", number, numberOfOne.Sum);

if (number == 444)
{
break;
}
}
Console.ReadLine();
}
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: