【问题标题】:happy number algo question solution not working快乐数字算法问题解决方案不起作用
【发布时间】:2020-11-27 21:38:46
【问题描述】:

试图解决这个编码问题:

编写一个算法来确定一个数字 n 是否“快乐”。

一个快乐的数字是由以下过程定义的数字:从任何正整数开始,将数字替换为其数字的平方和,并重复该过程,直到数字等于 1(它将保持不变),或者它在一个不包括 1 的循环中无限循环。这个过程以 1 结束的那些数字是快乐数字。

如果 n 是一个满意的数字,则返回 True,否则返回 False。

我做了一些工作,但我不确定我做错了什么。将不胜感激一些指针。谢谢!

function isHappy(numba1){
    let sum = 0;
    numba = numba1.toString().split('')
    let numbaArr = numba.map(y => parseInt(y))
    for (var x = 0; x< numbaArr.length; x++){
            sum += numbaArr[x] ** 2
    }
    if (sum > 1){
        isHappy(sum)
    }
    else if (sum === 1){
        return true
    }
    else if (sum <= 0){
        return false
    }
}

【问题讨论】:

  • 您需要先检查numba1 === 1 是否在进行其他操作。否则你会陷入无限循环
  • 同样嵌套的isHappy(sum) 根本不使用返回真/假
  • @Taplar 你能解释一下为什么这会导致无限循环吗?例如,说 numba1 是 19。在某些时候,总和将是一(这意味着它应该根据第二个 else if 语句返回 true)。但由于某种原因之后它恢复为未定义
  • 在您编辑问题之前,我是一个无限循环。原始代码在isHappy(sum) 调用周围没有if (sum &gt; 1)
  • @Taplar 是的,我编辑了它,但仍然不确定为什么这不起作用

标签: javascript algorithm recursion


【解决方案1】:

我看到你的回答有两个问题,一个小一个大。

  • Small:没有返回递归调用的值。这个:

    if (sum > 1){
        isHappy(sum)
    }
    

    应该是

    if (sum > 1){
        return isHappy(sum)
    }
    
  • Large:您没有做检查我们是否在相同值上循环的基本工作。例如在测试15,我们得到这些值

    15, 26, 40, 16, 37, 58, 89, 145, 42, 20, 4, 16
                ^^                              ^^
    

    我们可以退出了,因为我们已经看到16 两次了。 15 不高兴。但是对于44,我们得到

    44, 32, 13, 10, 1
    

    我们在没有骑车的情况下点击1,所以44 是一个快乐的数字。

    您的代码需要跟踪它迄今为止看到的值。

这是一种递归方法:

const digitsSquareSum = (n) => 
  String (n) .split ('') .map (n => n * n) .reduce ((a, b) => a + b, 0)

const _isHappy = (n, seen) =>
  n == 1
    ? true
  : seen .has (n) 
    ? false
  : _isHappy (digitsSquareSum (n), seen .add (n))

const isHappy = (n) => 
  _isHappy(n, new Set())

// display the happy numbers among the first 100 positive integers
console .log (Array .from ({length: 100}, (_, i) => i + 1) .filter (isHappy) .join(', '))

我们使用辅助函数来计算数字的平方和。这只是使主要功能更清洁。主函数_isHappy 是一个内部的私有函数,不会暴露给用户。它是递归的并维护我们已经看到的值的Set。如果我们的号码是1,我们返回true。如果我们的数字在我们已经看到的值集中,我们返回false。否则,我们将其添加到已经见过的集合中,通过调用我们的帮助器计算下一个测试用例,然后用这些调用 _isHappy

我们的公共函数只是调用这个主函数,创建初始空Set 的可见值,并将其与数字一起传递给测试。

在我们的演示中,我们使用Array .from ({length: 100}, (_, i) =&gt; i + 1),这是创建从1100 的整数数组的几种紧凑方法之一。在实践中,我会将其抽象为一个 range 函数,该函数采用 lohi 值并在它们之间创建一个整数数组,但这超出了这个答案的重点。

我们不必使用具有两个参数的内部递归函数和具有一个参数的公共函数的这种分解。我们可以使用这样的默认参数:

const isHappy = (n, seen = new Set()) =>
  console .log({n, seen}) ||
  n == 1
    ? true
  : seen .has (n) 
    ? false
  : isHappy (digitsSquareSum (n), seen .add (n))

但是这样做有一些潜在的问题。例如,我们不能像以前那样称呼它:

range(1, 100) .filter (isHappy)

因为filter 为其回调提供了额外的参数。它不仅提供值,还提供索引和整个数组。然而isHappy 认为第二个参数是所见值的Set;当它通过索引时,事情就会失败。我们可以这样做:

range(1, 100) .filter ((n) => isHappy (n))

但我们在写这种方式时总是要小心谨慎。我已经养成了只为控制调用方式的内部函数执行此操作的习惯。而且还是时不时会咬我。

【讨论】:

    【解决方案2】:

    保留一个看到的数字列表和 mod 10 得到最后一个数字,然后除以 10 和 floor 来移动数字:

    function sumSquares(num) {
        let sum = 0;
        while (num != 0) {
            sum += (num % 10) ** 2;
            num = Math.floor(num / 10);
        }
        return sum;
    }
    
    function isHappy(num) {
        const seen = new Set();
        while (num != 1 && !seen.has(num)) {
            seen.add(num);
            num = sumSquares(num);
        }
        return num == 1;
    }
    

    【讨论】:

    • 你不会返回递归调用的结果,也不会检查循环。
    猜你喜欢
    • 2021-02-01
    • 2021-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-09
    • 2015-06-19
    • 1970-01-01
    • 2020-08-31
    相关资源
    最近更新 更多