簡體   English   中英

在一個序列中找到m個總和為n的數字

[英]Find m numbers that sum to n in a sequence

給定一個從1 到 n的序列,我想找到所有大小為m且總和為n唯一子序列。 子序列不需要是連續的。 例如

if m = 2, n = 5
The possible unique subsequences of size 2 are {1,4} and {2,3}

到目前為止,我已經能夠使用遞歸生成所有子序列,但我的代碼不僅僅返回唯一的子序列,結果中有一些重復。

function allCombinations(m, n) {
if (m < 1) {
    return [];
}

let helper = function(m, n, arr, result, index){
    if (n < 0 || m < 0) {
        return 0;
    }

    if (m === 0 && n === 0) {
        result.push(arr.slice());
        return 1;
    }

    for (let i = index; i <= n; i++){
        arr.push(i);
        helper(m - 1, n - i, arr, result, index + 1);
        arr.pop();
    }

}

let result = [];
helper(m, n, [], result, 0);

return result;
}

和打電話時

let res = allCombinations(2, 5);

結果是

[ [ 1, 4 ], [ 2, 3 ], [ 3, 2 ] ]

如您所見,{3,2} 是 {2,3} 的副本。 如何更改我的代碼,使其僅返回唯一序列?

您可以通過使用i而不是index調用遞歸助手 function 來強制下一個選擇大於當前選擇:

for (let i = index; i <= n; i++){
    arr.push(i);
    helper(m - 1, n - i, arr, result, i + 1);
    arr.pop();
}

這將產生唯一的序列,其中元素按升序排序。 如果只用i調用它,則允許重復選擇。

除非您從包裝器 function 調用索引為 1 的助手,否則更改此項將允許選擇零:

let result = [];
helper(m, n, [], result, 1);
const res = allCombinations(2, 5);

const unique = res.reduce((acc, curr) => {
   const exists = acc.some(item => item.sort().toString() === curr.sort().toString());

   return exists ? acc : [...acc, curr]; 
}, []);

我會為這類問題推薦生成器 -

  1. 1..n中找到解決方案
  2. 大小為m
  3. 其中q是目標總和,初始化為n

 function* solve(n, m, q = n) { if (m == 0 && q == 0) yield [] else if (n == 0 || q < 0) return else { for (const s of solve(n - 1, m - 1, q - n)) yield [...s, n] yield *solve(n - 1, m, q) } } for (const p of solve(5, 2)) console.log(p) // [1,4] // [2,3]

我們可以通過使用解決方案的另一個默認參數s來折疊上面的for循環 -

 function* solve(n, m, q = n, s = []) // s = [] { if (m == 0 && q == 0) yield s else if (n == 0 || q < 0) return else { yield *solve(n - 1, m - 1, q - n, [n, ...s]) // update s yield *solve(n - 1, m, q, s) // pass s } } for (const p of solve(5, 2)) console.log(p) // [1,4] // [2,3]

我們可以使用提前return來折疊if語句 -

 function* solve(n, m, q = n, s = []) { if (m == 0 && q == 0) return yield s // <- if (n == 0 || q < 0) return yield *solve(n - 1, m - 1, q - n, [n, ...s]) yield *solve(n - 1, m, q, s) } console.log(JSON.stringify(Array.from(solve(5,2)))) // [[1,4],[2,3]] console.log(JSON.stringify(Array.from(solve(9,3)))) // [[1,2,6],[1,3,5],[2,3,4]] console.log(JSON.stringify(Array.from(solve(27,6)))) // [[1,2,3,4,5,12],[1,2,3,4,6,11],[1,2,3,4,7,10],[1,2,3,5,6,10],[1,2,3,4,8,9],[1,2,3,5,7,9],[1,2,4,5,6,9],[1,2,3,6,7,8],[1,2,4,5,7,8],[1,3,4,5,6,8],[2,3,4,5,6,7]]

如果您不喜歡solve上的額外參數,我們可以使用內部loop -

 function solve(n, m) { function* loop(n, m, q, s) // "helper" { if (m == 0 && q == 0) return yield s if (n == 0 || q < 0) return yield *loop(n - 1, m - 1, q - n, [n, ...s]) yield *loop(n - 1, m, q, s) } return loop(n, m, n, []) // n, m, q = n, s = [] } console.log(JSON.stringify(Array.from(solve(5,2)))) // [[1,4],[2,3]] console.log(JSON.stringify(Array.from(solve(9,3)))) // [[1,2,6],[1,3,5],[2,3,4]] console.log(JSON.stringify(Array.from(solve(27,6)))) // [[1,2,3,4,5,12],[1,2,3,4,6,11],[1,2,3,4,7,10],[1,2,3,5,6,10],[1,2,3,4,8,9],[1,2,3,5,7,9],[1,2,4,5,6,9],[1,2,3,6,7,8],[1,2,4,5,7,8],[1,3,4,5,6,8],[2,3,4,5,6,7]]

如果您不喜歡它公開生成器,您可以使用Array.from返回所有結果 -

 function solve(n, m) { function* loop(n, m, q, s) { if (m == 0 && q == 0) return yield s if (n == 0 || q < 0) return yield *loop(n - 1, m - 1, q - n, [n, ...s]) yield *loop(n - 1, m, q, s) } return Array.from(loop(n, m, n, [])) // Array.from } console.log(JSON.stringify(solve(5,2))) // solve now returns array // [[1,4],[2,3]] console.log(JSON.stringify(solve(9,3))) // <- // [[1,2,6],[1,3,5],[2,3,4]] console.log(JSON.stringify(solve(27,6))) // <- // [[1,2,3,4,5,12],[1,2,3,4,6,11],[1,2,3,4,7,10],[1,2,3,5,6,10],[1,2,3,4,8,9],[1,2,3,5,7,9],[1,2,4,5,6,9],[1,2,3,6,7,8],[1,2,4,5,7,8],[1,3,4,5,6,8],[2,3,4,5,6,7]]

隨心所欲地混合搭配這些技術!

暫無
暫無

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

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