[数学] 258. 各位相加 (循环,递归 → 数学推导)
258. 各位相加
题目链接:https://leetcode-cn.com/problems/add-digits/
分类:
- 数学:
- 反复做各位相加直到一位数 = 求“数根”
- 举例推导数学规律:数根 = num%9
- 简单证明:x*100+y*10+z=x*99+y*9+x+y+z
思路1:使用循环
不断获取num的每一位,叠加后覆盖为新的num,继续获取num的每一位求和,直到num是个位数时,返回num即可。
如何获取num的每一位?
num % 10 可得到个位
num /= 10 可将num的int形式右移一位
例如十位移动到个位,再执行num%10可以得到当前的个位,也就是实际的十位。以此类推。
实现代码:
class Solution {
public int addDigits(int num) {
int res = 0;
while(num / 10 > 0){//当num为个位数时退出循环
//取num的每一位求和
int backup = num;
int sum = 0;
while(backup > 0){
sum += backup % 10;
backup /= 10;
}
num = sum;//拿每一位叠加后的结果覆盖num
}
return num;
}
}
思路2:使用递归
- 递归函数功能:计算传递进来的参数的各位相加结果
- 递归出口:如果num是个位数,则直接返回num本身。
- 递归主体:计算num每一位之加sum,如果sum是个位数,则直接返回sum;如果sum不是个位数,则以sum为参数继续进入下一层递归。
实现代码:
class Solution {
public int addDigits(int num) {
//递归出口:num是个位数则直接返回num
if(num / 10 == 0) return num;
//计算num每一位之和
int sum = addDigits(num / 10) + num % 10;
//如果各位相加的结果是个位数则直接返回,不是个位数则继续对它进行按位求和
if(sum / 10 > 0) return addDigits(sum);
else return sum;
}
}
思路3:数学规律(数根 = num%9)
一个非负数的每一位相加之和称作“数根”,举例:
原数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
数根: 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3
可以发现,每个数的数根以1-9循环,所以一个数num的数根 = num % 9.
但存在一个特殊情况:
- 如果num是9的倍数,则它的数根是9,但num%9==0。
由此带来一个问题:代码如何编写能够同时兼容一般情况和特殊情况?
我们可以先将num-1, mod 9 ,最后再+1,例如:
原数: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
减一: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
模九: 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2 3 4 5 6 7 8 0 1 2
数根: 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 1 2 3
可以发现所有数字都可以统一用这样的方式处理。当然分情况讨论来实现也是完全可以的。
num的数根=num%9 这一结论只是通过举例推导出来的,还没有得到证明,在 https://leetcode-cn.com/problems/add-digits/solution/java-o1jie-fa-de-ge-ren-li-jie-by-liveforexperienc/233789 评论区看到一个很简洁巧妙的证明:
num = x*100+y*10+z = x*99+y*9+x+y+z。
其中对x*99和y*9做mod 9 都等于0,所以num % 9 = x + y + z = 数根。
实现代码:
class Solution {
public int addDigits(int num) {
return (num - 1) % 9 + 1;
}
}