关于一道面试题的分析与解答
给大家分享一下我第一次参加面试时的一个题目:
问题:对于任意一个正整数 N,按以下操作把它转化为一个单一数字(大于 0 小于 10的数):
把 N 的各位上数字相加,若得到的结果不是一个单一数字,就把结果的各位上的数字相加,
若得到的结果还不是一个一位数,就还把结果的各位上的数字相加,
……
直到结果为一个单一数字为止。
如:2345
2+3+4+5=14
1+4=5 结果就为 5。
请写出一个方法,当传入任意一个正整数时,返回它按以上操作所得到的单一数字。
分析:如何算出各位上的数字是关键,对于任意一个正整数 N 我们让它对 10 取模,就可以得它的个位数字,由此我们不难想出如下解法:
个位数字:n0=N%10
十位数字:n1=N/10%10
百位数字:n2=N/100%10
……
k 位数字:nk=N/10k%10
把 N1=n0+n1+n2+...+nk 的结果再按上述操作,然后再按上述操作,直到得到一个单一数字为止。由此我们有以下算法:
算法 1:递归算法:
1 public static int getSingleNum1(int N) {
2 int result = 0; // 保存返回结果
3
4 /*
5 * 每次循环让N模10,即得到相对应位上的数字, 用result来保存这个模10结果,
6 * 然后让N除10 直到N除10的结果等于0,停止循环
7 */
8 while (N > 0) {
9 result += (N % 10);
10 N /= 10;
11 }
12
13 /*
14 * 若result小于10(即已经为单一数字)直接返回
15 * 若大于等于10则对其进行同样的操作(递归),直到返回的结果小于10
16 */
17 if (result < 10) {
18 return result;
19 } else {
20 return getSingleNum1(result);
21 }
22 }
算法 2:对于一个递归算法我们可以对其进行消除递归:
1 public static int getSingleNum2(int N) {
2 int result = N; // 保存返回结果
3
4 /*
5 * 外层循环:每次把内层循环得到的结果赋值给N, 直到N的结果小于10为止
6 * 内层循环:每次循环让N模10,即得到相对应位上的数字,
7 * 用result来保存这个模10结果,然后让N除10 直到N除10的结果等于0,停止循环
8 */
9 while ((N = result) >= 10) {
10 result = 0;
11 while (N > 0) {
12 result += (N % 10);
13 N /= 10;
14 }
15 }
16 return result; // 返回结果
17 }
面试时我写的是第二种写法,但第二天早上我一觉醒来,又想了想这个面试的题目,越想越不对,越想越发现这个题目有些蹊跷:
数 2345 按题目所给的算法:
2+3+4+5=14
1+4=5
结果为 5
而 2345%9=5
再找一个数:67342
6+7+3+4+2=22
2+2=4
结果为 4
而 67342%9=4
我又找了一些数试试发现果然很蹊跷:
那就是把这些数直接模 9 就可以得到想要的结果(结果为 0 时为 9)。
要真是这样的话,那该怎么证明呢?经过我的认真分析和思考便有了以下的分析和证明:
设 N0 各位上的数字由低位到高位分别为 n0,1,n0,2,n0,3,……,n0,k0
则 N0=n0,1+n0,2*10+n0,3*102+...+n0,k0*10k0
令 N1=n0,1+n0,2+n0,3+...+n0,k0
设 N1 各位上的数字由低位到高位分别为 n1,1,n1,2,n1,3,……,n1,k1
则 N1=n1,1+n1,2*10+n1,3*102+...+n1,k1*10k1
令 N2=n1,1+n1,2+n1,3+...+n1,k1
……
令 Nm=n(m-1),1+n(m-1), 2+n(m-1),3+...+n(m-1),k(m-1)
设 Nm 各位上的数字由低位到高位分别为 nm,1,nm,2,nm,3,……,nm,km
则 Nm=nm,1+nm,2* 10+nm,3*102+...+nm,km10km
令 Nm+1=nm,1+nm,2+nm,3+...+nm,km
直到 Nm+1 为一个单一数字
以下证明 Nm+1=N0%9
由以上分析可知:
N0 |
=n0,1 =n0,1 |
+n0,2* 10 +n0,2 |
+n0,3* 102 +n0,3 |
+... +... |
+n0,k0* 10k0 +n0,k0 |
|
|
+n0,2* (10-1) |
+n0,3* (102-1) |
+... |
+n0,k0* (10k0-1) |
|
=N1 |
|
|
|
|
|
|
+n0,2* (10-1) |
+n0,3* (102-1) |
+... |
+n0,k0* (10k0-1) |
|
=n1,1 |
+n1,2* 10 |
+n1,3* 102 |
+... |
+n1,k1* 10k1 |
|
=n1,1 |
+n0,2* (10-1) +n1,2 |
+n0,3* (102-1) +n1,3 |
+... +... |
+n0,k0* (10k0-1) +n1, k1 |
|
|
+n1,2* (10-1) |
+n1,3* (102-1) |
+... |
+n1,k1* (10k1-1) |
|
|
+n0,2* (10-1) |
+n0,3* (102-1) |
+... |
+n0,k0* (10k0-1) |
|
…… |
|
|
|
|
|
=Nm+1 |
+nm,2* (10-1) |
+nm,3* (102-1) |
+.. . |
+nm,k*(10km-1) |
|
|
…… |
|
|
|
|
|
+n1,2* (10-1) |
+n1,3* (102-1) |
+.. . |
+n1,k1* (10k1-1) |
|
|
+n0,2* (10-1) |
+n0,3* (102-1) |
+... |
+n0,k0* (10k0-1) |
由于 10m-1在 m 为正整数时能整除 9,所以有:
Nm+1=N0%9
由此我们可以得出:
算法 3
1 public static int getSingleNum3(int N) {
2 return N % 9 == 0 ? 9 : N % 9;
3 }
如此一条语句就解决了问题!只是我当时在面试时没能想到这样做。如果是你,你会想到这种算法吗?