У меня есть set
случайно сгенерированных ints и функция evolve(set)
которая принимает набор, удаляет два ints и вставляет 4 новых ints. Я хочу, чтобы набор никогда не повторял ints. То есть независимо от того, сколько раз я применяю evolve(evolve(...evolve(set)))
, она никогда не должна иметь дублированных значений.
Что такое простой способ combine(int x, int y) → int
который гарантирует это свойство с высокой вероятностью?
// Helpers.
var range = length => Array.from({length}, i => i);
var random = () => (Math.random() * Math.pow(2,31) | 0);
var removeRandom = set => set.splice(random() % set.length, 1)[0];
var hasRepeated = set => !set.sort((a,b) => a - b).reduce((a,b) => a && a !== b && b || 0, -1);
// Receives two parent ints, returns 4 derived ints.
// Can't use random() here; it must generate 4 ints
// from simple functions (multiplication, bitwise
// operations, etc.) of 'a' and 'b'.
function combine(a, b) {
return [a + b + 0, a + b + 1, a + b + 2, a + b + 3];
};
// Removes two ints from set, inserts 4 ints.
function evolve(set) {
var a = removeRandom(set);
var b = removeRandom(set);
set.push(...combine(a,b));
};
// Random initial set of ints.
var set = range(64).map(random);
// No matter how many times 'evolve' is applied,
// the set should never have repeated ints.
for (var i = 0; i < 50000; ++i) {
evolve(set);
}
// Prints 'true' if algorithm is correct
// (no repeated number was generated).
console.log(!hasRepeated(set));
Обратите внимание, что здесь combine(a,b)
просто добавляет их вместе. Это плохой выбор; с целым 50000 звонками для evolve
, он уже не прошел тест. Я мог бы использовать линейный конгруэнтный генератор, но мне интересно, может ли он быть проще, чем при этих условиях. Возможно, использование XOR?
Если у вас есть пространство для хранения массива с юниверсом возможных записей, вы можете просто рандомизировать его, а затем отслеживать индексы, которые связывают ваш набор, увеличивая начальный индекс, чтобы удалить элементы и конечный индекс, чтобы добавить их.
Вы можете либо рандомизировать весь массив вперед, либо по мере увеличения индекса окончания.
const range = length => Array.from({length}, i => i);
иconst hasRepeated = set => (new Set(set)).size !== set.length