簡體   English   中英

你會如何調整我的遞歸 Coin Sum 算法解決方案?

[英]How would you tweak my recursive Coin Sum algorithm solution?

我正在處理一個硬幣總和問題:

給定一組可用面額和目標金額,我想獲得總和達到該目標金額的組合數。 對於每個面額,我可以隨心所欲。

例子:

輸入:

  • 面額:[1, 5, 10]
  • 目標數量:10

預期輸出:4

說明:我可以對相應的面額進行以下計數:

[10, 0, 0], [5, 1, 0], [0, 2, 0] 或 [0, 0, 1]

我的代碼

function func(denomenations, targetSum) {
  let totalCombos = 0;
  function generate(denomsLeft, remainder) {
    if(remainder === 0){
      totalCombos += 1;
      return
    }
    if(remainder - denomsLeft[0] >= 0) {
      generate(denomsLeft, remainder - denomsLeft[0])
    }
    if(remainder - denomsLeft[1] >= 0) {
      denomsLeft.splice(0,1)
      generate(denomsLeft, remainder - denomsLeft[0])
    }
  }
  generate(denomenations, targetSum)
  return totalCombos
}

問題

我確信我的解決方案非常接近,但有些東西有點偏離。

調用func([1,5,10],10)返回 3 而不是 4。我似乎沒有得到 5 & 5 = 10 的硬幣組合。

錯誤在哪里,我該如何解決?

您的代碼中有一些錯誤:

  • if(remainder - denomsLeft[1] >= 0) {應該有[0]而不是[1]

  • 你不應該用splice改變denomsLeft ,因為它會影響遞歸搜索的其余部分(也在回溯之后)的結果。 相反,創建一個沒有第一個元素的副本,並將其傳遞。

  • 此外,當您決定不再使用第一個面額時,您不應該從remainder扣除它。 因此,將這一點與上一點結合起來,您應該這樣做:

     generate(denomsLeft.slice(1), remainder)
  • 然后,您還需要檢查是否還有剩余的面額:

     if (!denomsLeft.length) return;

這將修復它。 但我也建議:

  • >=條件放在函數的開頭(與其相反,以紓困)。
  • 使用其他名稱而不是無意義的func
  • 始終使用分號結束語句,因為您不想將其留給解析器來決定。

所以這將是結果代碼:

 function func(denomenations, targetSum) { let totalCombos = 0; function generate(denomsLeft, remainder) { if (remainder < 0) return; if (remainder === 0){ totalCombos += 1; return } if (!denomsLeft.length) return; generate(denomsLeft, remainder - denomsLeft[0]) generate(denomsLeft.slice(1), remainder) } generate(denomenations, targetSum) return totalCombos } console.log(func([1,5,10],10)); // 4 console.log(func([1,2,5],5)); // 4

Trincot 對您的代碼出了什么問題以及如何修復它進行了出色的分析

不過,我想指出,有比問題中的方法和特林科特的清理方法更簡單的技術。

這是我可能會這樣做的方法:

 const coinCount = (denoms, target) => target == 0 ? 1 : denoms.length == 0 || target < 0 ? 0 : // else coinCount (denoms, target - denoms[0]) + coinCount (denoms.slice (1), target) console .log (coinCount ([1, 5, 10], 10)) console .log (coinCount ([1, 5, 10, 25], 100))

我們測試目標是否為0 如果是,我們返回1 如果這似乎令人吃驚,讓我們記住,一個辦法總零:我們在不返回幣!

如果目標不為零並且我們沒有剩余面額,或者如果我們的目標是負數,則沒有可用的硬幣組合,我們返回0

最后,我們可以做出選擇。 我們要么使用第一種面額的硬幣,要么不使用。 如果我們這樣做,那么我們會使用相同的一組面額重復出現,並且總數減去該面額的價值。 如果我們不這樣做,那么我們以后就不能使用它,所以我們用剩余的面額和當前的總數重新計算。 將這兩個選項返回的計數相加得到我們的總數。

我們可以看到遞歸是合理的,因為每個遞歸步驟要么減少我們正在搜索的總數(因此我們最終會找到一個不大於零的數字)或它減少面額的數量(因此我們最終會達到零。)無論哪種方式,我們最終都會達到我們的基本情況之一。

使用解構,我們可能會選擇一個變體:

const coinCount = ([denom = undefined, ...denoms], target) => 
  target == 0 
    ? 1
  : denom == undefined || target < 0
    ? 0
  : coinCount ([denom, ...denoms], target - denom) + coinCount (denoms, target)

在某些方面,我更喜歡這個變體,但任何一個似乎都更清晰地表達了問題中的基本遞歸。

我認為這種技術的任一變體總體上都更簡單,特別是因為原始技術取決於內部generate函數中的副作用。 這個版本是一個純函數,只使用一個表達式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM