鍍金池/ 問答/HTML/ 如何寫一個方法分析出一個正整數(shù)的和的所有可能性?

如何寫一個方法分析出一個正整數(shù)的和的所有可能性?

比如一個函數(shù)

let plus = (num)=>{
    //方法
}

plus(10)

返回的結(jié)果是這樣:

10 = 1+9;
10 = 1+2+3+4;
10 = 4+6;

總之就是返回這個參數(shù)所有的可能性。這個plus函數(shù)應(yīng)該怎么寫比較合適?

我的想法是用遍歷一個[1,2,3,4,5,6,7,8,9,10]這樣的數(shù)組,但是只能遍歷固定的層數(shù),比如說兩層,三層,但是這樣十分不靈活,求指教。

回答
編輯回答
舊城人

借鑒樓上的ciqulover提供的思路,感謝。
發(fā)現(xiàn)幾個問題,按照他的解法,有許多重復(fù)值,所以10的和的正整數(shù)組成的可能組合并沒有511種,而是通過過濾排序之后的41種。
所以重新寫了一個,其中重要的是在遞歸里面循環(huán)遍歷所有可能的值時,并不需要從頭遍歷到尾,比如

for(let i = 1; i < 10; i++) {}

而是遍歷前半部分就可以了

for(let i = 1; i <= 10 / 2; i++) {} 

這里之所以取等號是因為當正整數(shù)為偶數(shù)時,可以分解成相等的兩個數(shù)字,比如10 = 5 + 5。
還有取前半部分的原因是1 + 99 + 1組成實際上的結(jié)果是一樣的。

對首次生成的結(jié)果進行數(shù)組過濾和排序等等,得出下列代碼:

let results = [];

function plus(num, current = []) {
  let middle = num / 2;
  for (let i = 1; i <= middle; i++) {
    let j = num - i;
    let now = current.concat([i, j]);

    results.push(now);

    if (j > 1) {
      // 繼續(xù)分解j
      let next = current.concat([i]);
      plus(j, next);
    }
  }
}

// 過濾掉相同的值
function filterSameValueArray(arr) {
  arr = arr.map((item) => {
    return item.sort().join(',');
  });

  return Array.from(new Set(arr))
    .map((item) => {
      return item.split(',');
    });
}

plus(10);

// 按長度排序
results = results.sort( (a, b) => {
  return a.length - b.length; // 負值代表誰應(yīng)該在前面
});


results = filterSameValueArray(results).map(item => {
  return item.join(' + ');
});

console.log(`10的所有和的組成結(jié)果有${results.length}種,分別是:`);
console.log(results);

結(jié)果測試

clipboard.png

注意幾個點,關(guān)于數(shù)組的拷貝問題,concat拼接新數(shù)組不會對原數(shù)組造成污染,這里僅限于其數(shù)組元素沒有對對象的引用。而splice()會對原數(shù)組造成污染,倘若數(shù)組元素里面有對對象的引用的話,就要采用深拷貝等操作了。在這里,對于數(shù)組的過濾,我們可以巧妙地使用字符串比較的方法來判斷數(shù)組元素是否相等,前提是數(shù)組元素需要實現(xiàn)排好序。


如果以上有什么錯誤,歡迎輕拍。

2017年9月21日 20:00
編輯回答
生性

哎,好吧。Mask同學(xué)看出了問題,的確,那天寫答案已經(jīng)很晚就沒有做去重。還是被人發(fā)現(xiàn)了。。。?

現(xiàn)在補上。

const num = 10
const statck = []
const obj = {}
const pow = num => num ** num

function reduce(upper, before = []) {
    for (let i = 1; i <= upper / 2; i++) {
        const diff = upper - i
        const arr = [i, diff, ...before]
        const id = arr.map(pow).reduce((pre, cur) => pre + cur)
        if (!obj[id]) {
            statck.push(arr)
            obj[id] = 1
        }
        if (diff > 1) reduce(diff, [...before, i])
    }
}

reduce(num)

const result = statck.map(a => '10 = ' + a.join(' + '))
console.log(result)

一共41種。

2018年8月26日 14:12
編輯回答
莓森

我現(xiàn)在想到的最快的方法應(yīng)該是找到Z=1+2+3+...+X。。然后把1,2,3,...,X,做一個遍歷和的組合,去掉有重復(fù)數(shù)字的,就應(yīng)該是你想要的答案了。。比如10=1+2+3+4。。然后你就找到1,2,3,4的遍歷和的組合。。

1. 1,2=3 3+4+3 (重復(fù)數(shù)字)
2. 1,3=4 2+4+4 (重復(fù)數(shù)字)
3. 1,4=5 2+3+5
4. 1,2,3=6 4+6
5. 1,2,4=7 3+7
6. 1,3,4=8 2+8
8. 2,3=5 1+4+5
9. 2,4=6 1+3+6
10. 2,3,4=9 1+9
.
.
.

這樣子的形式。。

2018年5月6日 15:07
編輯回答
練命

數(shù)學(xué)上叫整數(shù)拆分,請參考百度百科

2018年7月13日 03:38