一、题目描述
给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。
二、思路与算法
各位相加,使用递归,出口是结果的长度等于1。
三、Java算法源码
public static int addDigits(int num) {
recursion(num);
return re;
}
static int re = 0;
private static void recursion(int num){
String str = String.valueOf(num);
int ret = 0;
for (int i = 0; i < str.length(); i++) {
ret += Integer.parseInt(String.valueOf(str.charAt(i)));
}
if(String.valueOf(ret).length() > 1){
recursion(ret);
}else{
re = ret;
}
}
注意char转int是有更好的方法的。Character.getNumericValue(str.charAt(i));
。
四、简化代码
时间复杂度为 O(1)O(1)的解法:
除个位外,每一位上的值都是通过 (9+1) 进位的过程得到的,想一下 拨算盘进位
把整数 n 看成 n 样物品,原本是以 10 个 1 份打包的,现在从这些 10 个 1 份打包好的里面,拿出 1 个,让它们以 9 个为 1 份打包。
这样就出现了两部分的东西:
原本 10 个现在 9 个 1 份的,打包好的物品,这些,我们不用管。
零散的物品,它们还可以分成:
从原来打包的里面拿出来的物品,它们的总和 =》 原来打包好的份数 =》 10进制进位的次数 =》 10 进制下,除个位外其他位上的值的总和
以 10 个 1 份打包时,打不进去的零散物品 =》 10 进制个位上的值。
如上零散物品的总数,就是第一次处理 num 后得到的累加值。
如果这个累加值 >9,那么如题就还需要将各个位上的值再相加,直到结果为个位数为止。也就意味着还需要来一遍如上的过程。
那么按照如上的思路,似乎可以通过 n % 9 得到最后的值。
但是有1个关键的问题,如果 num 是 9 的倍数,那么就不适用上述逻辑。原本我是想得到 n 被打包成 10 个 1 份的份数+打不进 10 个 1 份的散落个数的和。通过与 9 取模,去获得那个不能整除的 1,作为计算份数的方式,但是如果可以被 9 整除,我就无法得到那个 1,也得不到个位上的数。
所以需要做一下特殊处理,(num - 1) % 9 + 1。
可以这么做的原因:原本可以被完美分成 9 个为一份的 n 样物品,我故意去掉一个,那么就又可以回到上述逻辑中去得到我要的n 被打包成 10 个一份的份数+打不进 10 个一份的散落个数的和。而这个减去的 1 就相当于从,在 10 个 1 份打包的时候散落的个数中借走的,本来就不影响原来 10 个 1 份打包的份数,先拿走再放回来,都只影响散落的个数,所以没有关系。
public int addDigits(int num) {
return (num - 1) % 9 + 1;
}
惊呆了,代码还可以这样写?
🏆本文收录于,华为OD机试(JAVA)(2022&2023)
本专栏包含了最新最全的2023年华为OD机试真题,有详细的分析和Java解答。已帮助1000+同学顺利通过OD机考。专栏会持续更新,每天在线答疑。