https://leetcode.com/problems/add-digits/
Given a non-negative integer num
, repeatedly add all its digits until the result has only one digit.
For example:
Given num = 38
, the process is like: 3 + 8 = 11
, 1 + 1 = 2
. Since 2
has only one digit, return it.
Follow up:
Could you do it without any loop/recursion in O(1) runtime?
My Solution:
1. 最笨的办法是两次循环。里层循环执行将num的各个位相加,外层循环判断结果是否为个位数,是否还需继续执行各位相加。
int addDigits(int num) {
while(num > 9) {
int sum = 0;
while(num > 0) {
sum += num % 10;
num /= 10;
}
num = sum;
}
return num;
}
2. 考虑到输入参数int num,其表示成正整数最多10位,各位相加的和最大的数是1,999,999,999,相加之和sum1不超过82。而使得sum1的两位相加之和sum2最大的sum1取值为79,对应的sum2为16。令sum2的各位之和为sum3,。若sum2为两位数,则最大值是16,sum3为1+6=7;若sum2为1位数,则最大值是9,sum3=sum2=9。综上,给定32位正整数num,最多执行3次各位相加的操作即可得到最终结果。即num=>sum1=>sum2=>sum3。其中,num最多为10位,sum1为2位,sum2为2位,sum3一定为1位。故不循环,硬编码相加。
int addDigits(int num) {
// 第一次
int sum = num / 1000000000
+ (num / 100000000) % 10
+ (num / 10000000) % 10
+ (num / 1000000) % 10
+ (num / 100000) % 10
+ (num / 10000) % 10
+ (num / 1000) % 10
+ (num / 100) % 10
+ (num / 10) % 10
+ num % 10;
num = sum / 10 + sum % 10;// 第二次
num = num / 10 + num % 10;// 第三次
return num;
}
效率有提高,厚着脸皮不知道能不能算是O(1)。有很多无用计算是确实的。
3. 用数学方法计算代数解(恕我愚笨没有找到)。
4. Hint:找规律,发现当num从1开始递增时,结果为1-9不断循环。故规律为ret = (num-1) % 9 + 1;或 ret = num - (num - 1) / 9 * 9;
int addDigits(int num) {
return (num - 1) % 9 + 1;
}
正是我想要的结果。可这是看了三个Hint之后才想出来的。。
结论:可能是考研过了太久了,当初做无穷级数求和的题目就是先写出几项看看规律。现在连最基础的找规律都没试一试。以后谨记。
PS:找到规律后视图用数学进行证明,发现自己大致可以理解,就是当num自增1时,num的各位之和也自增1,或减去9k再自增1。而且,某个数减去9k之后,若其大于9,则在继续计算各位之和时,这个9k可以被抵消掉。但严谨的数学证明还是不会做。
请教ALF后得证:
证明:对任意n大于10,n与n的各位之和模九同余。(ai * 10^n = ai * (1 + 10^n - 1) = ai + ai * 999...999<i个9> = ai <mode 9>),不断地将结果的各位相加,最终得到一位数k。当k为1-8时,k和n模九同余,故k=n%9。当n%9为0时,k=9。
早知如此本科不如学数学!!