最大的奇约数

一直很习惯用java,但渐渐发现大神们都在用C++/C,在ACM中AC列表中的时间显著地体现了C++/C的速度优势。但今天恍然大悟,语言 doesn't matter, 算法 doesn‘t  matter ,这些都是工具,数学才是最令人敬畏的。

看似复杂的问题背后,苛刻的复杂度要求下,若能看破数字的奥秘,规律的实质,一切问题将迎刃而解。

举个例子来讲,今天遇到了一道网易笔试题——最大奇约数

小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11.
现在给出一个N,需要求出 f(1) + f(2) + f(3).......f(N)
例如: N = 7 
f(1) + f(2) + f(3) + f(4) + f(5) + f(6) + f(7) = 1 + 1 + 3 + 1 + 5 + 3 + 7 = 21

小易计算这个问题遇到了困难,需要你来设计一个算法帮助他。

先放上代码,我们再来解释。

import java.util.Scanner;

public class Main{

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		long n =  sc.nextLong();
		long sum = 0;
		for(long i =n;i>0;i/=2){
			long temp = (i+1)/2;
			sum+= temp*temp;
		}
		System.out.println(sum);
	}

}

我们不难发现,奇数的最大奇约数就是它自身。关键在于偶数。 对于偶数我们怎么处理呢?我们要用此偶数除以2,商若为奇数,那么我们得到了它的最大奇约数,若商为偶数,那么继续除以2,一直到商为奇数为止。

用一组数字来说明,当N为10 时,我们得到原始数列 1 2 3 4 5 6 7 8 9 10

 现在 i= 10;

将 1 3 5 7 9 挑出来, 我们还剩 2 4 6 8 10这5个偶数

现在 i = 5;

那么我们得到 1 2 3 45  ,这里面的 1 3 5 恰是 剩下的元素中 1 6 10 的最大奇约数。我们还剩2 4 这2个偶数

现在 i = 2;

对于偶数我们继续除以2  得到 1 2 ,这里面的1 恰是 剩下的元素中 2 的最大奇约数,我们还剩下 2这 1一个偶数

现在  i = 1;

对于偶数我们依旧除以2 得到1  好了,现在我们得到的序列没有偶数了,这个1 就是剩下的元素中 2 的最大奇约数。就可以到此结束了。(这里可以看到,8先是除以42得到4,但4是偶数,于是4再除以2得到 2,但2是偶数,所以2再继续除以2,得到1 ,到了奇数才结束)

现在我们总览全局,每一步我们都会挑出序列中的奇数来,那么挑出来的奇数必然是最后所有奇约数中的,既然要求所有的奇约数的和,那么我们为何不把每次挑出来的奇约数的和先求出来呢?  

那么每次挑出来的奇数的和与每次的i有什么关系呢? 我们可以看出每次挑出的奇数的和是 <=i的奇数的和哎! 那这样就好办了!等差数列求和公式走起!

当i是奇数的时候,利用求和公式 sum = (1 + i )/2*(1+ i )/2

当i是偶数的时候,利用求和公式 sum =  (1 + i -1)*i /2 ,即 i* i /2,那么这个式子 是不是等于   ((1+i)/2)  * ((1+i)/2) 呢? 答案是肯定的,因为 i是偶数啊,i+1后在除以2 是要强制取整的。 这样,我们就将i是奇数和偶数两种情况的计算式统一了起来。


这样,我们在用算法表达式将思路实现出来就不难了吧!




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值