繁体   English   中英

用随机非连续数字填充数组

[英]Fill an array with random non-consecutive numbers

我想创建一个数组( indexes ),它应该填充从0length - 1随机数。

所以如果length = 3; 那么indexes应该从0扩展到2 ,例如它可能是这样的: [0, 2, 1]

我们应该遵循一个条件:(上帝,我该如何用英语描述这一点:)

条件:我们不接受连续数字。

所以我们不应该返回:

[0, 1, 2]       => Because 0 and 1 and 2 are consecutive.

[2, 0, 1]       => Because 0 and 1 are consecutive.

[2, 3, 1, 0]    => Because 2 and 3 are consecutive.

好吧,我知道可能有一个例外,最后一个元素可能是连续的,因为那时我们别无选择!

我写了一段代码,但不幸的是,由于 CPU 使用率高,它使浏览器崩溃!

请帮助,我的笔记本电脑和我很困惑!

// generate number from 0 to max (max could include in the result)
function getRandom(max) {
    return Math.floor(Math.random() * (max + 1));
};

// our array to be filled with unordered numbers
let indexes = [];

// we will fill the above array with 0, 1 ,2 ,3 I mean 0 to (length - 1) 
let length = 4;

// loop through indexes so that it is filled with 4 elements
while( indexes.length <= length){

      // get a number randomally from 0 to 3
      let result = getRandom(length - 1);
       // we don't want any repeated number so..
       if(!indexes.includes(result)){     
          // finally here is our condition, we should   
          if( result !== indexes[indexes.length - 1] + 1 ){
              indexes.push(result);
          } else if(indexes.length == length){
            // push the last element to the array despite the condition
            indexes.push(result);
          }
       }

};

console.log(indexes);

您可以通过以下方式调整现代Fisher-Yates算法:

如果在索引值的交换,因为什么已经放置在指数ij将带来这是不允许出现在索引i的值+ 1,那么不这样做掉,而是做那些之间的三重旋转三个涉及的索引。

这是实现,以及 400 次运行的测试:

 function shuffled(n) { let a = [...Array(n).keys()]; for (let i = n - 1; i > 0; i--) { let j = Math.floor(Math.random() * (i + 1)); if (a[j]+1 === a[i+1]) { // a swap is going to violate the rule at i/i+1 // Triple rotation at j, i, i+1 (or, when j == i, swap at i, i+1) a[j] = a[i]; a[i] = a[i+1]--; } else { // standard swap let temp = a[i]; a[i] = a[j]; a[j] = temp; } } // Finally check first two values: if (a[0]+1 === a[1]) { let temp = a[0]; a[0] = a[1]; a[1] = temp; } return a; } // Test this solution: function verify(a) { let set = new Set(a); return !a.some((v, i) => v === a[i-1]+1 || !set.has(i)); } for (let size = 2; size < 6; size++) { for (let i = 0; i < 100; i++) { let a = shuffled(size); if (!verify(a)) throw "not correct"; } } console.log("tests successful");

这具有可预测的线性时间复杂度。 没有多次尝试失败的风险。

您的算法采用随机值,如果唯一剩下的值是最后一个值之前的值的增量值,那么最后一个值就会出现问题。

例如,取值为102 ,剩余值为3

          v
[1, 0, 2, 3]

在这种情况下,除了不需要的值外,没有其他可用值。 这会导致无限循环。


您可以获取一个包含所有索引的数组并使用Fisher-Yates shuffle 算法并进行shuffle,直到数组中没有连续的递增值。

 function shuffle(array) { // https://stackoverflow.com/a/2450976/1447675 var currentIndex = array.length, temporaryValue, randomIndex; // While there remain elements to shuffle... while (0 !== currentIndex) { // Pick a remaining element... randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; // And swap it with the current element. temporaryValue = array[currentIndex]; array[currentIndex] = array[randomIndex]; array[randomIndex] = temporaryValue; } return array; } let length = 4, indices = Array.from({ length }, (_, i) => i); do indices = shuffle(indices); while (indices.some((v, i, a) => v + 1 === a[i + 1])) console.log(...indices);

长度为 4 时,您的结果数组只有几个可能的结果(见下文)。

您的函数的问题在于,如果您以没有可能答案的数字开头,它将永远运行,并且只有 4 个可能的数字,发生这种情况的可能性非常高。 如果 0 或 3 作为第一个数字返回,它将永远找不到解决方案。 如果返回 1 并且第二个数字不是 3,或者如果 2 是第一个并且第二个数字不是 0,则相同,等等。更新,因为注释阐明允许降序连续数字(这看起来很奇怪)。

您还将永远运行,因为您的 while 循环应该使用indexes.length < length而不是<=

[0, 1, 2, 3] // no
[0, 1, 3, 2] // no
[0, 2, 1, 3] // yes
[0, 2, 3, 1] // no
[0, 3, 1, 2] // no
[0, 3, 2, 1] // yes
[1, 0, 2, 3] // no
[1, 0, 3, 2] // yes
[1, 2, 3, 0] // no
[1, 2, 0, 3] // no
[1, 3, 0, 2] // yes
[1, 3, 2, 0] // yes
[2, 0, 1, 3] // no
[2, 0, 3, 1] // yes
[2, 1, 0, 3] // yes
[2, 1, 3, 0] // yes
[2, 3, 0, 1] // no
[2, 3, 1, 0] // no
[3, 0, 1, 2] // no
[3, 0, 2, 1] // yes
[3, 1, 0, 2] // yes
[3, 1, 2, 0] // no
[3, 2, 0, 1] // no
[3, 2, 1, 0] // yes

这告诉我们,这个算法很可能会失败,因为当没有剩下的数字可以满足条件时,它没有“失败”条件处理。 您可以检查一下,如果是这种情况,请重新启动,但它仍然可能很慢。 一种不同的方法会更好。

这为下一个数字保留了一组可供选择的可能数字。

从这个集合中选出的下一个数字是随机选择的。

如果选择了连续的数字,则顺序交换。

不允许欺骗。

 function randomNonConsecutive(upto) { const result = [] let set = Object.keys([...Array(upto)]) for(let x = 0; x < upto; x++) { let index = Math.floor(Math.random()*set.length) let insert = set[index] if(x > 0 && Number(result[x-1]) === insert-1) { [result[x-1], insert] = [insert, result[x-1]] } result[x] = insert set.splice(index,1) } return result } let result = randomNonConsecutive(10) console.log(result)

更新:

我正在比较错误的数字以检查非连续规则

您可以创建一个索引列表,随机取第一项。 如果条件满足或者它是最后一个元素,则一次从索引中删除一项

 const range = (n) => { const array = []; for (let i = 0; i < n; i++) array.push(i); return array; }; const randomIndex = (array) => ( parseInt(array.length * Math.random()) ); const randomNonConsecutive = (n) => { const array = range(n); const result = array.splice(randomIndex(array), 1); while (array.length) { const last = result[result.length - 1]; const next = last + 1; const index = randomIndex(array); const item = array[index]; if (item !== next || array.length === 1) { result.push(item) array.splice(index, 1); } } return result; } console.log(randomNonConsecutive(3)) console.log(randomNonConsecutive(4)) console.log(randomNonConsecutive(5))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM