【问题标题】:Find all possible combinations which make a specific number JavaScript查找构成特定数字的所有可能组合 JavaScript
【发布时间】:2018-10-20 11:08:00
【问题描述】:

我的问题是我有一个数字,例如 17;我还有其他三个常数:2、5、7;

我需要找到使特定数字为 17 或任何其他数字的所有可能组合;

5 + 5 + 7 = 17 (1 combination)
5 + 5 + 5 + 2 = 17 (2 combinations)
2 + 2 + 2 + 2 + 2 + 7 = 17 (3 combinations)
2 + 2 + 2 + 2 + 2 + 2 + 5 = 17 (4 combinations)

所以答案是 4。 我创建了我的脚本,它在数字 17 上正常工作,但在 20 或 30 等更大的数字上出错。如何使它与所有数字一起工作?

const seek = 30;
const firstNum = 2;
const secondNum = 5;
const thirdNum = 7;
let combinations = 0;
const maxDivisor = Math.round(seek / 2);

for (let i = 1; i <= maxDivisor; i += 1) {
    if (secondNum * i + thirdNum === seek) {
        combinations++
    } else if (secondNum * i + firstNum === seek) {
        combinations++
    } else if (firstNum * i + secondNum === seek) {
        combinations++
    } else if (firstNum * i + thirdNum === seek) {
        combinations++
    } else if (thirdNum * i + firstNum === seek || thirdNum * i + secondNum === 0) {
        combinations++
    } else if (firstNum + secondNum + thirdNum === seek) {
        combinations++
    } else if (firstNum * i === seek || thirdNum * i === seek || secondNum * i === seek) {
        combinations++
    }
}
console.log(combinations);

【问题讨论】:

  • 在您的第二个组合中,您首先有一个 5,然后是一个 2,在第三个组合中,您首先有一个 2,然后是一个 7。所以您要数数吗:2 + 5 = 75 + 2 = 7作为两种组合?
  • 这是一个算术模问题,称为线性丢番图方程。建议你看this question

标签: javascript loops combinations


【解决方案1】:

简单的解决方案是首先计算每个数字的最大乘数,然后继续对所有可能的组合求和。

/** LOGIC **/

function getCombinations(inputNumber, pieceNumbers) {
  const combinations = []
  const initial = maxes(inputNumber, pieceNumbers);
  let divs = initial;
  const sum = createSum(pieceNumbers);
  while (!allZeros(divs)) {
    if (sum(divs) === inputNumber) {
      combinations.push(divs);
    }
    divs = decrement(divs, initial);
  }
  return combinations;
}

/**
 * returns max multiplier for each number
 * that is less than input number
 * ie. for [2, 5] and input 17
 * you get [8 (17 / 2); 3 (17 / 5)]
 */
function maxes(inputNumber, pieceNumbers) {
  return pieceNumbers.map((num, i) =>
    inputNumber / num | 0
  )
}

/**
 * decrements list of numbers till it contains only zeros
 * if we have divs [2, 0] and initial [2, 5] the result
 * will be [1, 5]
 */
function decrement(divs, initial) {
  const arr = divs.slice();
  let i = arr.length;
  while (i--) {
    if (arr[i] > 0) {
      return [...arr.slice(0, i), arr[i] - 1, ...initial.slice(i + 1)];
    }
  }
}

function allZeros(divs) {
  return divs.every(div => div === 0);
} 

function createSum(pieceNumbers) {
  return (divs) => divs.reduce((acc, itm, i) => acc + itm * pieceNumbers[i], 0);
}

function toPrint(combinations, pieceNumbers) {
  const printable = combinations.map(nums =>
    nums.map(
      (n, i) => Array(n).fill(pieceNumbers[i]).join(" + ")
    )
      .filter(x => x)
      .join(" + ")
  ).join("\n");
  return printable;
}

/** VIEW **/

const addPieceEl = document.querySelector(".js-add-piece-number");
const removePieceEl = document.querySelector(".js-remove-piece-number");
const calculateEl  = document.querySelector(".js-calculate");
const displayEl = document.querySelector(".js-display-result");

addPieceEl.addEventListener("click", () => {
  addPieceEl.insertAdjacentHTML("beforebegin", ` <input type="number" class="js-piece-number number" value="7" /> `)
})

removePieceEl.addEventListener("click", () => {
  addPieceEl.previousElementSibling.remove()
})

calculateEl.addEventListener("click", () => {
  const inputNumber = Number(document.querySelector(".js-input-number").value);
  const pieceNumbers = Array.from(document.querySelectorAll(".js-piece-number")).map(el => Number(el.value))
  const combinations = getCombinations(inputNumber, pieceNumbers);
  const total = `There are ${combinations.length} combinations for ${inputNumber} with ${pieceNumbers.join(", ")}:\n`;
  displayEl.textContent = total + toPrint(combinations, pieceNumbers);
});
.number {
width: 30px;
}
Input Number: <input type="number" class="js-input-number number" value="17"/>
<br/>
<br/>
Piece Numbers:
<input type="number" class="js-piece-number number" value="2"/>
<input type="number" class="js-piece-number number" value="5"/>
<input type="number" class="js-piece-number number" value="7"/>
<button class="js-add-piece-number">+</button>
<button class="js-remove-piece-number">-</button>
<br/>
<br/>
<button class="js-calculate">calculate</button>
<pre class="js-display-result"/>

【讨论】:

  • 干得好,没想到问题这么复杂。
【解决方案2】:

您可以测试所有组合

const n = 30;
console.log('Number to reach: n = ' + n);

const k = [7, 5, 2];
console.log('Numbers to use: k = ' + k);

console.log('n can be wrote: n = a*k[0] + b*k[1] + c*k[2]');
console.log('Let\'s found all combinations of [a, b, c]');
let t = [];
for (let a = 0; n >= a*k[0]; a++)
  for (let b = 0; n >= a*k[0] + b*k[1]; b++)
    for (let c = 0; n >= a*k[0] + b*k[1] + c*k[2]; c++)
      if (n == a*k[0] + b*k[1] + c*k[2])
        t.push([a, b, c]);

console.log('Number of combinations: ' + t.length);
for (let i = 0; i < t.length; i++)
  console.log(
    n + ' = ' + new Array()
    .concat(new Array(t[i][0]).fill(k[0]).join(' + '))
    .concat(new Array(t[i][1]).fill(k[1]).join(' + '))
    .concat(new Array(t[i][2]).fill(k[2]).join(' + '))
    .filter(e => e.length > 0)
    .join(' + ')
  );

【讨论】:

    【解决方案3】:

    我假设您只想要在 2+55+2 不是唯一的意义上独一无二的解决方案。

    使用递归,您可以创建一种算法来解决每个数字和每个常量列表的问题。

        const seek = 17;
        const numbs = [2,5,7];
        const minNum = Math.min(...numbs);
        let numberOfCombinations = 0;
    
        seekCombinations(seek, numbs);
    
        function seekCombinations (toSeek, numbs) {
            for (let i = 0; i < numbs.length; i++) {
                let newToSeek = toSeek - numbs[i];
    
                if (newToSeek === 0) { //you found a combination
    
                    numberOfCombinations++;
    
                } else if (newToSeek >= minNum) { //The new number to seek can still form a combination
    
                    //remove numbers from your list of constants that are smaller then then the number that is already in your current combination so you'll only get unique solutions.
                    let index = numbs.indexOf(numbs[i]);
                    let newNumbs = numbs.slice(index, numbs.length);
    
                    //recursively call seekCombinations
                    seekCombinations (newToSeek, newNumbs, currentCombination)
                }
            }
        }
    

    【讨论】:

      【解决方案4】:

      那么问题是什么? 你的脚本有什么问题或者怎么做?

      如果你错过了,

      将数字与i 相乘并不能解决此问题。因为:

      30 = 2 + 2 + 5 + 7 + 7 + 7
      30 = 2 + 2 + 2 + 5 + 5 + 7 + 7
      

      这 3 个常量中的任意一个都可以出现在此处。

      您的脚本未涵盖这些情况

      【讨论】:

      • 对不起,我错过了,我的问题是如何处理所有数字
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-20
      相关资源
      最近更新 更多