题目要求:给出一个非负整数num,重复的将num各个位上的数字加在一起,一直得到的结果是个位数。
如:num=38,则3+8=11,1+1=2。最后得到个位数字2.
令:你可以不用循环和递归完成这道题吗?并要求其时间复杂度为O(1)
解题思路:方法1:本来我是按照最一般的方法来做的,就是将38转换为字符串,然后字符串上的各个字符转换为数字相加,加到一起之后再转换为字符串,判断字符串的字符 数是不是1,如果是就结束,不是的话继续循环。
方法2:这种方法就比较简单了,这种方法是用了一个规律:任意一个整数关于9取余就等于这个整数各个位的数加在一起的数关于9取余。即:
设自然数N=a[n]a[n-1]…a[1]a[0],其中a[0]、a[1]、…分别是N的个位,十位…上的数。再设M=a[0]+a[1]+…+a[n]。则M mod 9=N mod 9。
证明:
∵ N=a[n]a[n-1]…a[0]=a[n]*10^n+a[n-1]*10^(n-1)+…+a[1]*10+a[0].
又∵ 1 mod 9=1 mod 9,
10 mod 9=1 mod 9,
10 mod 9=1 mod 9,
…
10^n mod 9 =1 mod 9.
上面这些等式两边分别同乘以a[0]、a[1]、a[2]、…、a[n],再相加得:
a[0]+a[1]*10+…+a[n]*10^n≡(a[0]+a[1]+…+a[n])(mod 9),
即 M mod 9=N mod 9,得证。
根据上面的定理我们可知,重复的将num的各个位上的数字加在一起,不管加了多少次得到的数字关于9取余都是相等的,都等于最后得到的个位 数字,即38 mod 9=11 mod 9 =2 mod 9 =2。也就说这个过程中得到的各个数是关于9同余的。所以我们只需要把num关于9取余就可以得 到结果了,但是要注意当余数为0时应当返回9。
程序实现:方法1:
class Solution {
public:
int addDigits(int num) {
string s = num2str(num);
int n;
while (s.size()>1){
n = 0;//一开始写程序的时候忘记每次循环的过后要把n置零了,导致程序超时,结果错误。
for (int i = 0; i < s.size(); i++){
n = n + (int) s[i] - 48;
}
s = num2str(n);
}
return (int) s[0] - 48;
}
string num2str(int i){
stringstream ss;
ss << i;
return ss.str();
}
};
方法2:
class Solution {
public:
int addDigits(int num) {
if(num==0)
return 0;
else
return num%9==0?9:num%9;
}
};
当然也可以直接return 1+(num-1)%9;
总结:在方法1上面浪费了很多时间,一开始以为是string.size()返回值不是整形的所以与有符号的整形数1进行比较会出问题,所以才没办法跳出循环,但是单步执行了一下才发行是因为每次循环过后没有将n置零,这样就会在上一次循环过后的n值叠加到结果上面,所以就会出问题。不过学会了怎么调试怎么加断点怎么单步执行。方法2是上网上搜了一下才知道这个规律的,这种加的方法得到的数称为digital root 数字根。
参考:
http://www.cnblogs.com/Rinyo/archive/2012/12/20/2826755.html
http://blog.youkuaiyun.com/xudli/article/details/47786855