一. 题目描述
给定一个非负整数 num
,反复将各个位上的数字相加,直到结果为一位数。
示例:
输入: 38
输出: 2
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2 是一位数,所以返回 2。
进阶:
你可以不使用循环或者递归,且在 O(1) 时间复杂度内解决这个问题吗?
二. 代码
emmm, 拿到这道题, 瞬间就想到了循环的解法,感叹,这是一道多么简单的题目,然后, 直接翻到进阶的要求, 直接傻眼了,这要怎么才能实践O(1)?这里面难道还有什么深藏的数学不成。
然后, 翻了一些博客, 发现,真的藏着其数学特性。这里先贴一下代码。(最后附有代码出处)
/**
* 功能说明:LeetCode 258 - Add Digits
* 开发人员:Tsybius2014
* 开发时间:2015年8月25日
*/
public class Solution {
/**
* 给定整数不断将它的各位相加,直到相加的结果小于10,返回结果
* @param num
* @return
*/
public int addDigits(int num) {
return (num - 1) % 9 + 1;
}
}
三. 解析
1. 这个解法,乍一看,我是懵的,凭什么对9求余,就可以直接得到结果了。所以,我就好好学习了一把。
2. 为了方便后续翻看我参考的文章(其实也可以说是转载了), 我也一样假设输入的数字是一个5位数字num,那么num的各位分别为a、b、c、d、e。
有如下关系:num = a * 10000 + b * 1000 + c * 100 + d * 10 + e
即:num = (a + b + c + d + e) + (a * 9999 + b * 999 + c * 99 + d * 9)
其中,a * 9999 + b * 999 + c * 99 + d * 9 一定可以被9整除,也就是说 num % 9 == ( a + b + c + d + e ) % 9。
3. 我们可以继续假设 num2 = ( a + b + c + d + e ),那么这个num2的位数最大不超过两位,不失一般性,这里假设num2为2位数。
则根据第二步的推论,可得出: num2 = k1 * 10 + k2
即: num2 = (k1 + k2) + ( k1 * 9 )
最终得出:num2 % 9 == (k1 + k2) % 9, 那么到这里就比较明朗了,由于 (k1 + k2) < num2 ( k1 > 0 的情况下), 只要不断迭代下去最终k1 + k2 < 10 的情况必定会出现,而我们需要保留的就是最终这个k1 + k2 的值。
4. 由以上的推到可以得出,num % 9 == (k1 + k2) % 9,且k1 + k2 < 10 的情况就是我们需要的结果。而当k1 + k2 < 9时, k1 + k2 % 9 == k1 + k2,但是这个式子并不能适应于k1 + k2 == 9的情况,所以修改了一下,就变成了( k1 + k2 - 1 ) % 9 + 1 的形式。转换一下,就是(num - 1) % 9 + 1 == ( k1 + k2 - 1) % 9 + 1。