簡體   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