1)最大约数问题:
对于给定的两个正整数a,b,计算a和b之间约数个数最多的数。比如:a=1,b=36,1和36之间约数个数最多的是36,个数是9.
思路:普通的方法就是循环测试a和b之间每一个数到底有多少个约数,然后逐一比较
1第一次尝试:
int number=0;//统计约数的个数
int flag=0;//设置比较数,当后一个数的约数个数大于前一个数时,重置
for(int i=a;i<=b;i++)//外层循环从a到b
{
//for(int j=0;j<=i;j++)//内层循环检测从1到自身
//修改为:
for(int i=1;j<=i;j++)//程序员总是以为自己不会犯这种低级错误
//在以后的生活中提醒自己肮脏的过去是为了迎接光明的未来
{
if(i%j==0)
{
number++;
}
}
if(number>flag)//重置标志位
{
flag=number;
}
number=0;//刚才忘记恢复计数值为0
}
第二次尝试:在时间复杂度上,能否缩短运算的时间,通过观察发现,当内层循环运行到自身的一半,直到最后自身,才发现有一个约数存在,那就是它本身,例如:数字100,当超过50,51,52,53.。。。一直到99再也没有100的约数,我们通过修改上面的程序减少运算的复杂度,循环次数减少一半,在空间浮点数运算上面(在此,提醒读者本人水平有限,没有深入了解计算机如何进行除法运算的,请见谅)
所以程序修改如下:
int number=0;//统计约数的个数
int flag=0;//设置比较数,当后一个数的约数个数大于前一个数时,重置
for(int i=a;i<=b;i++)//外层循环从a到b
{
for(int j=1;j<=i/2;j++)//内层循环检测从1到自身
{
if(i%j==0)
{
number++;
}
}
number++;//自身也是一个约数,需添加进去
if(number>flag)//重置标志位
{
flag=number;
}
number=0;//刚才忘记恢复计数值为0
}
现在基于上面的思想:1、如果这个数不能被2整除,范围会缩短一半
2.如果这个数也不能被3正确,范围接着变小
3.发现一个规律就是尝试用素数表里面的数去整除这个数,范围更加小了
且慢,我们以为已经到了极限,但是一个更大的问题来了:
只要它是偶数绝对会比奇数拥有更大的约数。当然了,我们需要考虑到a和b的范围,相邻的两个数之间偶数的约数的个数必然不会小于奇数的约数个数(除了1和2之外),例如:12和13,80和81,因此,这个条件成立下,循环次数将再一次下降一半。
第三次尝试:因此选择跳过奇数的测试直接比较两个偶数的约数个数,代码如下:
原文地址:http://5228690.blog.51cto.com/5218690/1580842