是否可以生成一组随机的数字,这些数字相乘就可以得出一个特定的数字?

时间:2019-07-10 05:55:40

标签: javascript algorithm logic

是否存在一种算法,可以将数字分解为一个由单个数字组成的 随机集 ,如果将这些数字相乘,最终得到的数字就是给定的相同数字?

generatePossibility(number, size = 8)
  

请注意,我每次输入相同的数字时,都不应退还相同的数字。

例如:如果我输入了数字940800,它将生成以下内容(大小11):

  • [5, 8, 7, 7, 1, 1, 1, 2, 5, 8, 6]
  • [3, 4, 1, 2, 4, 5, 5, 8, 7, 7, 1]
  • [8, 3, 8, 5, 2, 7, 5, 2, 7, 1, 1]

*数字不必唯一。


  

更新

我意识到在这种情况下并非所有数字都可以。但是,就我而言,由于我是设置数字的人(不是任何用户免费输入的东西),所以我想知道一种算法,可以将一个数字分解为一定大小的一位数字数组。 / p>

我当前的算法效率很低而且不够漂亮:

例如:数字为940,800

  1. 生成一个随机的单个数字数组(不包括0),最多可乘以940,800
  2. 如果大小小于8,则将其余空间加1
  3. 如果大小大于8,请尝试删除1s
  4. 如果大小大于8,请尝试删除双精度2或双精度3来减小尺寸
  5. 如果大小大于8,则不能使用此随机数集。
  6. 生成一组新的数字

function isPrime(num) {
  for(var i = 2; i < num; i++)
    if(num % i === 0) return false;
  return num > 7; // Return any prime number that is not single digit
}

function shuffle(array) {
  // Shuffle the array
  return array.sort(() => Math.random() - 0.5);
}

function randomInt() {
  // returns 1 - 9
  return Math.floor((Math.random() * 9) + 1);
}

function removeElement(array, elem) {  
  const index = array.indexOf(elem);
  if (index > -1) {
      array.splice(index, 1);
  }
}

const shrink = (array, number) => {
  removeElement(array, number);
  removeElement(array, number);
  array.push(number * number);
  return array;
}

const expand = (array, number) => {
  array.push(number);
  array.push(number);
  removeElement(array, number * number);
  return array;
}

const getRandomDigits = (number, size) => {
  let remaining = number;
  const list = [];
  while (remaining !== 1) {
    if (isPrime(remaining)) {
      return `Unable to proceed, stuck at prime number ${remaining}`;
    }
    const randomNumber = randomInt();
    if (Number.isInteger(remaining / randomNumber)) {
      // Possible number, save it into the list
      list.push(randomNumber);
      // Update the remaining
      remaining /= randomNumber;
    }
  }
  return list;
}

const adjustSize = (array, size) => {
  // sort the array in ascending order
  let remaining = array.sort((a, b) => a - b);
  
  // if size is lower than desired size
  // find count of 4, if there is one, split them into double 2
  while (remaining.length < size && remaining.find(e => e === 4)) {
    remaining = expand(remaining, 2);
  }
  // find count of 9, if there is one, split them into double 3
  while (remaining.length < size && remaining.find(e => e === 9)) {
    remaining = expand(remaining, 3);
  }
  // add rest of the space with 1
  while (remaining.length < size) {
    remaining = remaining.push(1);
  }
  
  // If remaining has number "1", we can simply remove them
  while (remaining.length > size && remaining.includes(1)) {
    remaining.shift();
  }
  // combine possible integers
  // find count of 2, if there are two, combine them into single 4
  while (remaining.length > size && remaining.filter(e => e === 2).length > 1) {
    remaining = shrink(remaining, 2);
  }
  // find count of 3, if there are two, combine them into single 9
  while (remaining.length > size && remaining.filter(e => e === 3).length > 1) {
    remaining = shrink(remaining, 3);
  }
  // the given number is impossible
  while (remaining.length > size) {
    return `Couldn't generate, please try again! Size: ${remaining.length}`;
  }
  
  // possible
  return remaining;
}

let endResult = null;
let failedAttempt = 0;

while (!endResult && failedAttempt < 100) {
  const randomDigits = getRandomDigits(940800, 12);
  
  if (typeof randomDigits === 'string') {
    console.error(randomDigits);
    failedAttempt += 1;
    continue;
  }
  
  const attempt = adjustSize(randomDigits, 12);
  
  if (typeof attempt === 'string') {
    console.error(attempt);
    failedAttempt += 1;
    continue;
  }
  // Found it
  if (Array.isArray(attempt)) {
    endResult = shuffle(attempt);
  }
}

console.log('Failed attempt', failedAttempt);
console.log('Succeeded Result', endResult);

这有点用,但是很丑。

4 个答案:

答案 0 :(得分:2)

首先算出数字的素数。例如,940800是:

2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 3 * 5 * 5 * 7 * 7

然后,要生成这些随机数组之一,请将上面设置的任意数字(或无)随机相乘在一起,直到获得数组中所需项的数量(此处为8)。例如,您可以使用Math.random()随机选择两个索引(不替换)。例如,假设选择的索引是0和1-那么您将拥有

4 * 2 * 2 * 2 * 2 * 2 * 2 * 3 * 5 * 5 * 7 * 7

也许下一个随机指数是5和8-然后,您将5和8指数相乘:

4 * 2 * 2 * 2 * 2 * 10 * 2 * 3 * 5 * 7 * 7

重复此操作,直到获得所需数量的项目为止。如果需要,您还可以在返回数组之前先对数组进行洗牌。

要将输出数组限制为个​​位数,请在上述过程中,仅在结果小于10时乘以-否则,请重新选择索引。 (对于某些输入,将无法解决,例如generatePossibility(1000, 1)。)

答案 1 :(得分:2)

天真的实现部分基于@CertainPerformance建议

function findPrimeFactors(num) {
  var primeFactors = [];
  while (num % 2 === 0) primeFactors.push(2), num = num / 2;
  for (var i = 3; i <= Math.sqrt(num); i++)
    while (num % i === 0) primeFactors.push(i), num = num / i;
  if (num > 2) primeFactors.push(num);
  return primeFactors;
}

function generatePossibility(number, size) {
  var factors = findPrimeFactors(number).sort().reverse();
  var ret = new Array(size).fill(1);
  for (i = 0; i < factors.length; i++) {
    var indexes = new Array();
    ret.filter((a, idx) => {
      if (a * factors[i] < 10)
        indexes.push(idx);
    });
    var randIdx = Math.floor(Math.random() * (indexes.length > 0 ? indexes.length : size));
    if (indexes.length > 0)
      ret[indexes[randIdx]] *= factors[i];
    else
      ret[randIdx] *= factors[i];
  }
  return ret;
}
var possibilities = generatePossibility(940800, 8);
console.log(possibilities.join(","));
console.log(possibilities.reduce((a, b) => a * b));


获取数字的阈值(因子的单个数字组合的最小数组大小):

function findPrimeFactors(num) {
  var primeFactors = [];
  while (num % 2 === 0) primeFactors.push(2), num = num / 2;
  for (var i = 3; i <= Math.sqrt(num); i++)
    while (num % i === 0) primeFactors.push(i), num = num / i;
  if (num > 2) primeFactors.push(num);
  return primeFactors;
}

function getThreshold(num) {
  var factors = findPrimeFactors(num).sort().reverse();
  if (factors.filter(a => a > 10).length > 0) return -1;
  var ret = [factors[0]];
  factors = factors.slice(1);
  while (factors.length > 0) {
    if (ret[ret.length - 1] * factors[0] > 10)
      ret.push(factors[0]);
    else
      ret[ret.length - 1] *= factors[0];
    factors = factors.slice(1);
  }
  return ret.length;
}

console.log(getThreshold(940800));

答案 2 :(得分:0)

不可能。至少不是只有一位数字数字。

为什么?

因为,假设数字的一个因素是13、17、19、11 ...等,换句话说,一个因素是两位数或三位数的质数怎么办?

答案 3 :(得分:-1)

由于并非每个自然数都使之成为可能,因此将数字绘制为一组数字1、2、3、5、7的复数会更有效(甚至不需要知道乘积)。

现在,如“某些性能”所建议的那样,您可以合并一些数字以将长度减少到所需的值,并避免因素总是相同的。

例如

多重图

1 1 1 1 2 2 2 3 3 3 3 5 7 7

减少到长度8

1 1 1 1 2 2 2 3 3 9 5 7 7
1 1 1 2 2 3 3 9 5 7 7
1 1 2 2 3 3 9 5 7 7
1 1 2 6 3 9 5 7 7
1 1 6 6 9 5 7 7

现在您可以随机播放了。

对于另一个图形,请从最初的多重性重新开始,形成新的合并和新的改组。

请注意,某些情况下会死胡同(无法达到所需的长度)。可达到的最大长度是初始多重性的总和。最小值就像M2/3 + (M2 mod 3)/2 + M3/2 + M5 + M7之和,如果1M2 mod 3=1是奇数(如果我是对的话),则减去M3


(对不起,Python)

l= 9 # Sequence length
n= 5 # Maximal multiplicities

# Generate the prime digits with multiplicities (0 to n-1)
while True:
    p= [1] * random.randrange(n) + [2] * random.randrange(n)\
     + [3] * random.randrange(n) + [5] * random.randrange(n)\
     + [7] * random.randrange(n)
    if len(p) >= l:
        break

# Try to generate ten sequences
for s in range(10):
    # Keep a copy
    q= copy.deepcopy(p)

    # Merge digits to the desired length (aborts after 50 attempts)
    count= 50
    while len(q) > l and count > 0:
        i= random.randrange(len(q))
        j= random.randrange(len(q))
        if i != j and q[i] * q[j] < 10:
            # Merge
            q[i]*= q[j]
            del q[j]
        count-= 1

    if count > 0:
        random.shuffle(q)
        print(q, functools.reduce(operator.mul, q, 1))

[7, 3, 1, 5, 3, 2, 7, 7, 5] 154350
[7, 3, 7, 7, 3, 5, 5, 2, 1] 154350
[2, 3, 1, 3, 5, 7, 7, 7, 5] 154350
[5, 3, 7, 2, 5, 1, 3, 7, 7] 154350
[3, 7, 3, 7, 5, 5, 2, 7, 1] 154350
[2, 7, 3, 7, 7, 1, 3, 5, 5] 154350
[7, 7, 3, 3, 5, 7, 2, 5, 1] 154350
[5, 2, 3, 7, 7, 5, 7, 3, 1] 154350
[7, 7, 2, 1, 5, 3, 7, 5, 3] 154350
[7, 1, 7, 5, 5, 2, 3, 7, 3] 154350