【问题标题】:How does this function calculate?这个函数是怎么计算的?
【发布时间】:2017-04-11 15:30:01
【问题描述】:

我一直在研究 CodeWars katas,发现有人想出了一个非常酷的解决方案。我的问题是我不明白它是如何工作的。我了解其中的一些,例如它通常在做什么,但不了解细节。是不是自己回来了?它是如何进行计算的?有人可以向我解释一下,因为我真的要学习如何做到这一点。如果您知道我可以阅读或观看的任何其他资源,那将很有帮助。我在 Swift 文档中没有看到类似的内容。

    func findDigit(_ num: Int, _ nth: Int) -> Int {
           let positive = abs(num)

           guard nth > 0 else { return -1 }
           guard positive > 0 else { return 0 }
           guard nth > 1 else { return positive % 10 }

           return findDigit(positive / 10, nth - 1) }        

对于上下文:

说明:

函数 findDigit 将两个数字作为输入,num 和 nth。它输出num的第n位(从右到左计数)。

注意

如果 num 为负数,忽略其符号并将其视为正值。 如果 nth 不是正数,则返回 -1。 请记住 42 = 00042。这意味着 findDigit(42, 5) 将返回 0。

例子

findDigit(5673, 4) 返回 5

findDigit(129, 2) 返回 2

findDigit(-2825, 3) 返回 8

findDigit(-456, 4) 返回 0

findDigit(0, 20) 返回 0

findDigit(65, 0) 返回 -1

findDigit(24, -8) 返回 -1

非常感谢任何帮助。谢谢。

【问题讨论】:

  • 个位是数字 mod 10。如果要求提供个位,请给出。否则考虑数字 div 10 并给出它的第 n-1 个数字(与原始数字的第 n 个数字相同)。它是递归(定义:见递归)。
  • 这也是一个很好的例子,你可以(在我看来)使用guard混淆代码。
  • 马丁说得很好。

标签: function return swift3


【解决方案1】:

这是一个递归解决方案。它本身不会返回自己,它会在更简单的情况下调用自己,直到它到达基本情况(这里是一个 1 位数字)。因此,例如,让我们跟踪它在您的第一个示例中的作用: findDigit(5673, 4) 调用 findDigit (567, 3) 调用 findDigit (56,2) 调用 findDigit (5,1) 这是返回 5 的基本情况,它一直冒泡回到表面。

【讨论】:

  • 感谢您的帮助。
【解决方案2】:

这是一个递归算法。它的工作原理是通过将原始问题简化为同一时间的较小问题,然后递归地解决该问题,直到遇到 基本情况

如果您看到正在拨打的电话,我认为您会更容易理解它。当然,最好在调试器中单步执行以真正了解发生了什么。我已经对感兴趣的部分进行了编号,以便在下面引用它们

func findDigit(_ num: Int, _ nth: Int) -> Int {
    print("findDigit(\(num), \(nth))") //#1
    let positive = abs(num) // #2

    guard nth > 0 else { return -1 } // #3
    guard positive > 0 else { return 0 } // #4
    guard nth > 1 else { return positive % 10 } // #5

    return findDigit(positive / 10, nth - 1) // #6
}

print(findDigit(5673, 4))
  1. 我打印出函数和它的参数,你能看到发生了什么吗?这是打印的内容:

    findDigit(5673, 4)

    findDigit(567, 3)

    findDigit(56, 2)

    findDigit(5, 1)

    5

  2. num 的正值,这样- 符号就不会碍事。

  3. 断言nth 变量大于0。由于这个问题中的数字计数,任何等于小于0 的值都是无效的。在这种情况下,将返回 -1这是 Swift 中非常糟糕的做法。这就是 Optionals 存在的目的。最好让这个函数返回Int? 并返回nil 来表示nth 变量中的错误。

  4. 断言positive 变量大于0。唯一可能的情况是positive 为0,在这种情况下,它的数字(对于任何位置)是0,这就是为什么你有return 0

  5. 断言nth 大于1。如果不是这种情况,那么 nth 必须为 1(编号为 #3 的守卫确保它不能为负数,或者 0。在这种情况下,十进制数的第一位数字是该数字模 10,因此返回 positive % 10

  6. 如果我们到达这条线,我们知道我们有一个合理的值 nth (> 0),它不是1,我们有一个大于 0 的正数。现在我们可以继续通过递归来解决这个问题。我们将正数除以 10,并使其成为新的nth,然后我们将递减nth,因为这个电话的nth 数字是什么,将在下一个电话的n-1 th 位置打电话。

【讨论】:

  • 感谢您的帮助。
【解决方案3】:

这是一个简单的递归函数。递归意味着它一遍又一遍地调用自己,直到满足结束递归的条件。如果条件永远不满足,你最终会得到一个无限递归,这不是一件好事:)

由于您已经了解该函数的用途,以下是其内部工作原理的详细信息:

// Saves the absolute value (removes the negative sign) of num
let positive = abs(num)

// Returns -1 if num is 0 or negative
guard nth > 0 else { return -1 } 

// Returns 0 if the absolute value of num is 0 (can't be negative)
guard positive > 0 else { return 0 } // Could be guard positive == 0

// nth is a counter that is decremented with every recursion.
// positive % 10 returns the remainder of positive / 10
// For example 23 % 10 = 3
// In this line it always returns a number from 0 - 9 IF nth <= 0
guard nth > 1 else { return positive % 10 }

// If none of the above conditions are true, calls itself using
// the current absolute value divided by 10, decreasing nth.
// nth serves to target a different digit in the original number
return findDigit(positive / 10, nth - 1) 

让我们一步一步地运行一个例子:

findDigit(3454, 3)
num = 3454, positive = 3454, nth = 3
-> return findDigit(3454 / 10, 3 - 1)

num = 345, positive = 345, nth = 2 // 345, not 345.4: integer type
-> return findDigit(345 / 10, 2 - 1)

num = 35, positive = 35, nth = 1
-> return 35 % 10
-> return 5

【讨论】:

  • 非常感谢您的解释。实际上,我只是将问题标记为已回答,因为有人在 CodeWars 上回复了我。解释比你的要轻得多,但我明白了。再次感谢您提供的详细信息。
  • 感谢您将其标记为已回答!在 Codewars 上玩得开心!
【解决方案4】:

CodeWars 上名叫 JohanWiltink 的人回答了我的问题。但我选择接受 Nicolas 的细节。

这是 JohanWiltink 的解释:

函数不会将自身作为函数返回;它使用不同的参数调用自身并返回该递归调用的结果(这可能是嵌套的,在本例中为 nth=1)。

findDigit(10,2) 因此返回 findDigit(1,1) 的值。

如果您没有看到它是如何工作的,请尝试手动计算,例如findDigit(312,3) 会返回。

非常感谢所有回答的人!真的很感激!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多