女友校招笔试编程题:网易测试岗-买苹果和求最大奇约数

嗯,这算是人生中第一次正式写博客吧。以前一直将笔记记录到网络笔记本上,自己没事的时候会翻翻笔记回顾总结一下自己。

但是前段时间在某个场合提到了“技术需要分享”,嗯,是的,技术需要分享,想来自己也看不少大牛的技术博客,大牛一般都是非常乐于分享自己的技术的!作为一个小菜鸟,我也要像技术大神们学习,分享菜鸡的技术成长历程。一是希望通过自己的分享尽量能够帮助到一些人,同时希望在这个过程中能够提升自己的语言组织与逻辑表达能力。

文章中肯定会有或大或小的错误,希望读到我文章的朋友能够在评论里及时指明,我会第一时间给改正!以前比较少写正规的文章,做笔记的时候比较随意,格式排版配图什么的可能刚开始不太好,但凡事总有开始,肯定会越来越好的。

顺便提一嘴,我目前使用的语言是Java。

好了,不瞎BB了,分享技术,享受技术!go~


女友最近在找工作,参加各种公司的校招,每次笔试完后都会和我分享其中的一些题目,中秋放假做一个算是阶段性总结的总结吧!

第一题:

[编程题] 买苹果
时间限制:c/c++,1s,其他语言3s
空间限制:32768K,其他语言忘记了...
题目描述:
小易去附近的商店买苹果,奸诈的商贩使用了捆绑交易,只提供6个每袋和8个每袋的包装(包装不可拆分)。
可是小易现在只想购买恰好n个苹果,小易想购买尽量少的袋数方便携带。

如果不能购买恰好n个苹果,小易将不会购买。
输入描述:
输入一个整数n,表示小易想购买n(1 ≤ n ≤ 100)个苹果
输出描述:
输出一个整数表示最少需要购买的袋数,如果不能买恰好n个苹果则输出-1
输入样例:
20
输出样例:
3


解析:这道题不难,就是考察2元一次方程的最值问题,中学生都会.....

设,容量为6的袋子数量为a,容量为8的袋子的数量为b,使用的袋子总数为x,则以上问题可由如下方程组表示:(请忽略很丑的字体,重点是内容)


然后,用b表示a,经过一些运算可以得到如下结果:(请忽略很丑的字体,重点是内容)


再然后,需要注意的是,因为是要求x的最小值,所以当b最大时,x最小,所以实现时需要注意一下,b从最大的可选值开始取就可以了。

然后根据上面的思路就可以进行代码实现啦!具体代码如下:

import java.util.Scanner;

public class wangyi1 {

	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		while (scan.hasNext()) {
			int n = scan.nextInt();
			System.out.println(getSum(n));
		}
	}

	public static int getSum(int n) {
		int sum = -1;
		int a = 0;
		int b = 0;
		int m = n / 8;
		for (int i = m; i >= 0; i--) {
			if ((n - 8 * i) % 6 == 0) {
				b = (n - 8 * i) / 6;
				a = i;
				sum = a + b;
				break;
			}
		}
		return sum;
	}
}

第二题:

[编程题|20分] 最大的奇约数
时间限制:c/c++,1s,其他语言3s
空间限制:32768K,其他语言忘记了...

题目描述:
大的奇约数
小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题:
定义函数 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
小易计算这个问题遇到了困难,需要你来设计一个算法帮助他。

输入描述:
输入一个整数N (1 ≤ N ≤ 1000000000)
输出描述:
输出一个整数,即为f(1) + f(2) + f(3)…….f(N)
输入样例:
7
输出样例:

21

解析:这道题的解题过程也是充满了艰辛......

当时的解题过程是这样的:

首先,先对n以内的所有奇数直接用公式求和。

其次,就考虑偶数的情况,偶数分两种:2的n次幂的数和非2的n次幂的数。设这个偶数为a,对a进行开方,这个开方的结果也分两种:整数和浮点数。如果开方的结果是整数,则判断是奇数还是偶数,如果是奇数则返回,如果是偶数则对Math.sqrt(a)递归这个操作。如果开方的结果是浮点数,则对a / 2递归这个操作。这样就可以得出结果。下面是实现的代码。下面的图是当时的推导过程,有些乱,大家可以自己拿草纸推导一下。

import java.util.Scanner;

/**
 * 方法1:时间复杂度并不高,但是耗时过长(开方运算耗时长)
 * 
 * @author Administrator
 * 
 */
public class wangyi2_a {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		while (scan.hasNext()) {
			int n = scan.nextInt();
			// long t1 = System.currentTimeMillis();
			System.out.println(getsum(n));
			// long t2 = System.currentTimeMillis();
			// System.out.println("total time=" + (t2 - t1));

			// System.out.println("sqrt time=" + sqrtTime);
		}
	}

	// static int sqrtTime = 0;

	static int f(int x) {
		if ((x & 1) == 1) {
			return x;
		}
		// long t1 = System.currentTimeMillis();
		// 经测试,开方运算过于耗时
		double sqrt = Math.sqrt(x);
		int k = (int) Math.floor(sqrt);
		int up = (int) Math.ceil(sqrt);
		// long t2 = System.currentTimeMillis();
		// long t3 = t2 - t1;
		// sqrtTime += t3;
		if ((k & 1) == 1) {
			return k;
		} else {
			if (k == up)
				return f(k);
			else {
				return f(x >> 1);
			}
		}
	}

	static int getsum(int n) {
		int m = 0;
		int maxj = 0;
		int t = 0;
		if ((n & 1) == 0) {
			m = n >> 1;
			maxj = n - 1;
			t = n;
		} else {
			m = n >> 1 + 1;
			maxj = n;
			t = n - 1;
		}
		int sum = (1 + maxj) * (m >> 2);
		for (int i = 2; i <= t; i = i + 2) {
			sum += f(i);
		}
		return sum;
	}

}

是的,正如上面的代码中注释的那样,提交之后,结果超时了......代码的循环次数其实并不多的,但是“时间复杂度”这个东西嘛,也是要考虑某个操作的耗时情况的。正如上面代码中的注释那样,Math.sqrt()方法是很耗时的,读者朋友们可以自己打开注释去看看,开方运算占用了大部分的运算时间。既然这样都不行,那只有一种可能,这个东西真的是有公式或者说规律的。好那现在就来分析怎么找规律......

设sum(i) = f(1) + f(2) + ... + f(i);
求sum(i)的过程中,对于f(i), i 为奇数可以直接求,就是 i 本身。
问题就是求所有f(i), i为偶数的和。
因为要求的是最大奇约数,

所以f(2k) = f(k) + 1 + 3 + ... + 2k - 1  ,

所以f(2) + f(4) + ... + f(2k) = f(1) + f(2) + ... + f(k)  + 1 + 3 + ... + 2k - 1  
所以
当i 为偶数时,sum(i) =  sum (i / 2) + 1 + 3 + ... + i - 1 
当i 为奇数时,sum(i) =  sum (i - 1) +  i

所以,根据这个思想,代码如下:

import java.util.Scanner;

/**
 * 方法2:动态规划方法
 * 
 * @author Administrator
 * 
 */
public class wangyi2_b {
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		while (scan.hasNext()) {
			int n = scan.nextInt();
			System.out.println(getsum(n));
		}
	}

	static int getsum(int n) {
		if (n == 1) {
			return 1;
		}
		if (n % 2 == 0) {
			return getsum(n / 2) + n * n / 4;
		} else {
			return getsum(n - 1) + n;
		}
	}
}

 这样,终于完成了这道题。 


ps:第一次写技术类博客,各种经验不足,图片也不会插入,排版也不太熟,写了好久,不足之处还请指出,非常感谢,我自己之后也会把现在不足的地方改正。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值