【问题标题】:Coding Challenge, trying to solve recursively. help on caching using Closure编码挑战,尝试递归解决。帮助使用 Closure 进行缓存
【发布时间】:2019-07-11 07:39:28
【问题描述】:

问题: / step(x) 操作的工作原理如下:它将数字 x 更改为 x - s(x),其中 s(x) 是 x 的数字之和。 //你喜欢对数字应用函数,所以给定数字 n,你决定构建一个递减的数字序列:n, step(n), //step(step(n))等,以0为最后一个元素。

// 构建单个序列对您来说是不够的,因此您将序列的所有元素替换为它们的数字之和 (s(x))。 //现在你很好奇哪个数字最常出现在新序列中。如果有多个答案,则返回最大的一个。

// 示例

// - 对于 n = 88,输出应该是 // mostFrequentDigitSum(n) = 9.

// 这是你构建的第一个序列:88, 72, 63, 54, 45, 36, 27, 18, 9, 0;

// 这里是每个元素的 s(x):16, 9, 9, 9, 9, 9, 9, 9, 9, 0。

// 可以看到,第二个序列中出现频率最高的数是9。

// - 对于 n = 8,输出应该是 // mostFrequentDigitSum(n) = 8.

// 一开始你构建了以下序列:8, 0

// 每个元素的 s(x) 为:8, 0

// 如您所见,答案是 8(它出现的频率与 0 一样多,但大于它)。

所以我看了这个问题,似乎递归在这里会很好。我确信有一种更简单的方法可以迭代地完成它,但我也试图在递归方面做得更好,所以我使用递归进行了尝试。

let cache = {}

function recursiveCall ( x ) {
    if( x == 0 ) { return 'dog' } // we dont need to return anything, because after each recursive call we are saving cache[sumOfX] in our cache,
    //once we get to the very TOP of our stack when it hit 0.  We have already made our object, and therefore do not even need a return statement.


    //get the sum of our digits for x.
    let sumOfX = x.toString().split('').map( n => { return Number(n)}).reduce( (sum, num) => {
        sum += num;
        return sum;
    },0);

    //creates a key for a sumOfX and makes the value 1 if it hasnt been seen or increments the value if it has been seen.
    if( !cache[sumOfX] ) {
        cache[sumOfX] = 1;
    } else {
        cache[sumOfX]++;
    }



    console.log(x);
    console.log(sumOfX);
    recursiveCall( x - sumOfX );
    console.log(cache)
}



function mostFrequentDigitSum( digit ) {
//create our cache using our recursive call
recursiveCall(digit);

//find the largest value in that object.
let max = 0;
let value = 0;
for(var key in cache) {
    if( max < cache[key]) {
        max = cache[key];
        value = Number(key);
    }
}
return value;
}


console.log(mostFrequentDigitSum(88));

console.log(cache);

我使用递归创建了一个对象。不过,我必须为我的缓存创建一个全局变量,并且我希望我的代码是自包含的。我试图做一些事情来让它作为一个闭包工作,但仍然没有想出一个解决方案。任何提示都会有所帮助,因为如果有另一种递归解决此问题的方法,我正试图在递归方面做得更好,所以我不会看其他人的代码。使我的工作以递归方式并在一个自包含的闭包中也将非常有帮助。谢谢。

【问题讨论】:

    标签: javascript recursion closures


    【解决方案1】:

    您可以让recursiveCall 接受第二个参数cache,默认为{}

    function recursiveCall(x, cache = {}) {
      if (x == 0) {
        return cache;
      }
      // ...
      return recursiveCall(x - sumOfX, cache);
    }
    

    在第一次调用recursiveCall 时,将创建cache 对象;在随后对recursiveCall 的递归调用中,您可以将该对象作为第二个参数传递。当您到达递归结束时,return cache 使其返回到初始调用:

    function mostFrequentDigitSum(digit) {
      //create our cache using our recursive call
      const cache = recursiveCall(digit);
    

    然后您可以使用该cache 变量来计算要从mostFrequentDigitSum 返回的valuecache 现在不是全局的,每次调用 mostFrequentDigitSum 时都会重新创建它(或者更准确地说,每次外部调用 recursiveCall 时)。

    function recursiveCall(x, cache = {}) {
      if (x == 0) {
        return cache;
      }
      //get the sum of our digits for x.
      let sumOfX = x.toString().split('').map(n => {
        return Number(n)
      }).reduce((sum, num) => {
        sum += num;
        return sum;
      }, 0);
    
      //creates a key for a sumOfX and makes the value 1 if it hasnt been seen or increments the value if it has been seen.
      if (!cache[sumOfX]) {
        cache[sumOfX] = 1;
      } else {
        cache[sumOfX]++;
      }
      return recursiveCall(x - sumOfX, cache);
    }
    
    
    
    function mostFrequentDigitSum(digit) {
      //create our cache using our recursive call
      const cache = recursiveCall(digit);
    
      //find the largest value in that object.
      let max = 0;
      let value = 0;
      for (var key in cache) {
        if (max < cache[key]) {
          max = cache[key];
          value = Number(key);
        }
      }
      return value;
    }
    
    
    console.log(mostFrequentDigitSum(88));

    或者,在保持相同逻辑的同时精简代码:

    function recursiveCall(x, cache = {}) {
      if (x === 0) {
        return cache;
      }
      const sumOfX = x.toString().split('').map(Number).reduce((a, b) => a + b, 0);
      cache[sumOfX] = (cache[sumOfX] || 0) + 1;
      return recursiveCall(x - sumOfX, cache);
    }
    
    function mostFrequentDigitSum(digit) {
      //create our cache using our recursive call
      const cache = recursiveCall(digit);
      //find the largest value in that object.
      return Object.entries(cache).reduce((a, b) => a[1] > b[1] ? a : b, [null, 0])[0];
    }
    console.log(mostFrequentDigitSum(88));
    console.log(mostFrequentDigitSum(8));
    console.log(mostFrequentDigitSum(0));

    【讨论】:

      【解决方案2】:

      这是递归

      const objOfFinalSums={}
      function solution(n) {
          const numToString = n.toString().split('')
          let sum = numToString.reduce( (accumulator, current_value) => accumulator+=parseInt(current_value),0)
          objOfFinalSums[sum] ? objOfFinalSums[sum]++ : objOfFinalSums[sum] = 1;
          return !sum == 0 ? solution(n-sum) : parseInt(Object.keys(objOfFinalSums).reduce( (accumulator,current_value) => objOfFinalSums[current_value] >= objOfFinalSums[accumulator] ? accumulator=current_value : accumulator, 0))
      }
      

      【讨论】: