我在LeetCode上遇到问题,需要复习递归。这是个问题:
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.
我已经看到了使用while循环的答案,但我想尝试使用递归。 这就是我到目前为止所做的:
public int AddDigits(int num) {
if(num > 9)
{
num = (num%10) + (num/10);
AddDigits(num);
}
else{
return num;
}
}
首先,我得到"Not all code paths return a value."
,但基于if
布尔检查,这不应该没问题吗?即使我在else块之后添加return num
,我仍然得到11.使用29的输入,我的解决方案返回11,即使num
最终变为2.使用上面的递归解决方案,{ {1}}部分发生了几次(我用Console.WriteLine语句测试过) - 这是由于堆栈吗?
这就是我想知道的 - 为什么代码在递归调用之后发生 - 或者递归调用通常不包括递归调用之后的代码?
另外,如何使用递归并且不使用while循环?
答案 0 :(得分:3)
您需要在两个路径中返回值(if和else)。
可能是这样的(将AddDigits(num);
更改为return AddDigits(num);
也有效(在其他答案中给出),顺便说一下我不知道为什么,但它有效)
public int AddDigits(int num, bool root = true) {
if(num > 9)
{
var sum = num;
if(root)
{
while(sum > 9)
{
sum = AddDigits(sum/10, false) + sum%10;
}
return sum;
}
else return AddDigits(num/10, false) + num%10;
}
else{
return num;
}
}
像这样调用函数
var result = AddDigits(123456789); // ;)
这就是算法的工作原理。
AddDigits(123456789) (root of call) 45 (45 is bigger than 9. AddDigits(45) 9 is not bigger than 9. return result.
|| /\ repeat. while(sum > 9)) || /\
\/ || \/ ||
9 + AddDigits(12345678) || 4 + AddDigits(5)= 9
|| ||
\/ 9+8+7+6+5+4+3+2+1 = 45
9 + 8 + AddDigits(1234567) ||
|| ||
.... ||
|| ||
\/ ||
9+8+7+6+5+4+3+2+1 (now going back and summing them all)
答案 1 :(得分:2)
这里有一个提示,不会产生正确的值,但它会让你到那里。
(另一个提示,你的函数需要带两个参数)
public int AddDigits(int num) {
if(num > 9)
{
num = (num%10) + (num/10);
return AddDigits(num);
}
else{
return num;
}
}
编辑:Python中的解决方案
def ra(n):
if n > 0:
return n % 10 + ra(n / 10)
else:
return 0
答案 2 :(得分:1)
以下是使用Linq的示例:
using System.Linq;
static int Singularize(int val)
{
string str=val.ToString();
int rslt=Enumerable.Range(0,str.Length).Select(i => str.Substring(i,1)).Select(int.Parse).Sum();
return (rslt.ToString().Length==1) ? rslt : Singularize(rslt);
}
返回递归调用本身(必要时)允许CLR离开当前调用并转移到递归调用并重用相同的堆栈项。如果保留当前调用(通过使递归调用将其结果返回到当前调用),递归链中的每个调用都会将骆驼(堆栈)上的另一个吸管丢回,直到骆驼断开 - 即堆栈溢出错误。
答案 3 :(得分:1)
所以真的有两种不同的操作,这两种操作都可以递归地说明。
操作1是将数字的所有数字加在一起:
int AddAllDigits(int n)
{
return n < 10 ? n : (n % 10 + AddAllDigits(n / 10));
}
操作2是继续执行操作1,直到我们只有一个数字:
int ReduceToSingleDigit(int n)
{
return n < 10 ? n : ReduceToSingleDigit(AddAllDigits(n));
}
所以现在我们可以
ReduceToSingleDigit(123456789); //gives 9
现在,如果我们有C#6的优点,我们可以通过将它们缩减为表达式主体而不是语句主体来使我们的递归函数看起来更时尚(或令人困惑,具体取决于您的位置)。
int ReduceToSingleDigit(int n) => n < 10 ? n : ReduceToSingleDigit(AddDigits(n));
int AddDigits(int n) => n < 10 ? n : (n % 10 + AddDigits(n / 10));
可爱。