【问题标题】:How to recursively reduce a number by multiplying its digits?如何通过将数字相乘来递归地减少数字?
【发布时间】:2020-01-23 17:54:04
【问题描述】:

现在,我们有了这个递归函数:

function digitsMultipication(number) {
  let strNumber = number.toString();
  let firstNum = parseInt(strNumber[0]);

  if(strNumber.length==1){
    return firstNum
  }else{
    let x = ''
    for(i=1;i<strNumber.length;i++){
        x += strNumber[i]
    }
    x = parseInt(x)
    return firstNum * digitsMultipication(x);
  }
}

// TEST CASES
console.log(digitsMultipication(66)); // 36

我们如何编辑这个函数,因为我们希望输出条件是一个数字。 因为 36 仍然是 2 位,我们希望函数再次递归,直到输出为一位,即 8。

66 => 6 * 6 = 36,
36 => 3 * 6 = 18,
18 => 1 * 8 = 8(想要的最终输出)

【问题讨论】:

  • 将字符串的第一个数字乘以字符串其余部分的digitsMultiplication。例如,result("1234") = 1 * result("234") = 1 * 2 * result("34"),等等。您的“基本情况”将是您只有 2 个或更少的剩余数字。
  • 我从你的解释中了解到,最终结果是24(1*2*3*4)。但是我们想要的是函数再次递归,直到它得到一位数的结果。因此,最终结果应该是 8 (2*4)。因为 24 仍然是 2 位数
  • 签出this

标签: javascript recursion


【解决方案1】:

你的意思是这样的吗?

const
  get = num => {
      const sum = [...num + ''].reduce((sum, n) => n * sum);
      return sum < 10 ? sum : get(sum);
  },
  result = get(66);

console.log(result);

更有效的方法是避免字符串化,只使用数学:

const
  get = num => {
      let sum = 1;
      
      while (num) {
        sum *= num % 10;
        num = parseInt(num / 10);
      }
      
      return sum < 10 ? sum : get(sum);
  },
  result = get(66);

console.log(result);

甚至可以节省内存并避免递归:

const
  get = num => {
    let sum = 1;

    for (;;) {
      sum *= num % 10;
      num = parseInt(num / 10);

      if (num <= 0) {
        if (sum < 10) return sum;

        num = sum;
        sum = 1;
      }
    }
  },
  result = get(66);
  
console.log(result);

【讨论】:

  • 没错!但我无法理解你的想法。如果您不介意,您可以向我们解释这个想法,以使其更清楚
  • @AndersonPimentel 当然。要将数字转换为数组,您可以使用toString 函数,但您只需将数字添加到字符串中,它就会自动转换。然后,要将字符串转换为数组,您可以使用 Array.fromsplit('') 函数之一,但您可以使用扩展运算符简单地破坏字符串。对我来说它更优雅。就是这样。
  • @AndersonPimentel num 为 66。+'' 将其转换为字符串。扩展运算符...num 将其转换为['6','6']
  • @ratavagn 我将数字转换为字符串,以便我可以轻松地逐一访问它所包含的数字。我将它们一个一个相乘(使用reduce),然后 - 如果总和小于 10(因此是个位数) - 我返回它,如果不是,我继续下一轮。
  • [...num + ''].reduce((sum, n) =&gt; Number(n) * sum) - 这不适用于负数。您也不需要使用Number(),因为无论如何乘法都会将两个操作数强制转换为数字。
【解决方案2】:

首先让我们编写两个简单的函数:

  1. mult - 倍数 ab

    const mult = (a, b) => a * b;
    
    mult(3, 4);
    //=> 12
    
  2. prod - 将列表的所有元素相乘。

    const prod = (...ns) => ns.reduce(mult);
    
    prod(1, 2, 3, 4);
    //=> 24
    

我们如何将一个数字(我们假设为正整数)拆分为数字?
即从123[1, 2, 3]。有许多种方法可以做到这一点。对于这个答案,我将使用:

const to_digits = n => Array.from(String(n), Number);

to_digits(123);
//=> [1, 2, 3]

现在让我们重构你的函数(我称之为prod_digits):

const prod_digits =
  n =>
      Math.abs(n) < 10  ? n
    : n < 0             ? prod_digits(prod(-1, ...to_digits(Math.abs(n))))
                        : prod_digits(prod(...to_digits(n)));
                        
                        
console.log(prod_digits(66));  //=> 8
console.log(prod_digits(-66)); //=> -8
console.log(prod_digits(6));   //=> 6
console.log(prod_digits(-6));  //=> -6
<script>
const to_digits = n => Array.from(String(n), Number);
const mult = (a, b) => a * b;
const prod = (...n) => n.reduce(mult);
</script>

优化

作为练习,您可以实现两个提前退出条件:

  1. 如果to_digits 返回一个包含0 的列表,则只返回0
  2. 如果to_digits 返回一个仅由1 组成的列表,则只返回1

【讨论】:

  • 为什么不无条件使用Math.abs,并去掉n &lt; 0周围的分支?如果你想继续分支,那么我认为- nMath.abs(n) 更干净。
  • @ScottSauyet 不确定您的确切意思。我需要n &lt; 0 检查在prod(...) 调用中潜入-1,因此它返回否定结果。例如-123 ~> prod(-1, 1, 2, 3) === -6
  • 哦,对了。我更喜欢“数字乘积”上的正号。但如果你想要可能的负面结果,显然你需要一些东西。对于那个很抱歉。不过,另一个变体是n =&gt; Math.abs(n) &lt; 10 ? n : prod_digits(prod(Math.sign(n), ...to_digits(Math.abs(n)))),尽管这在 IE 中可能不起作用。
猜你喜欢
  • 1970-01-01
  • 2019-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 2018-05-09
  • 2020-08-22
  • 2018-02-09
相关资源
最近更新 更多