2011-06-28 19 views
1

我需要做什麼來生成符合我具體標準的給定範圍內的非重複整數序列?當生成隨機序列時的尷尬標準

這裏有標準:只有

  1. 使用1和MAX之間的數字(比如說9)。
  2. 數字在序列內不能重複,除了:
    2a。序列中前兩個數字必須重複。
    2b。這兩個數字必須在最終序列的最後5個位置內的隨機點重複(最後5個包括重複)。

例如: SET: 1,2,3,4,5,6,7,8,9

隨機序列(具有重複):
2,4,6,9,3,1,5,2,8,7,3
r, , , ,r, , ,x, , ,x

在這裏,我已表明,隨機選擇要重複的數目(從第一的5以隨機順序排列)與r以及它們隨機放置(插入最後序列的最後5個)的插入點與x

任何幫助解決這一點非常感謝。實際使用會比這更復雜一點,但是我知道一旦我能夠實現這一目標,我需要做些什麼。

編輯

爲了澄清多一點,我有1-20,我需要一個22位的隨機序列。每個數字都必須使用,兩個將被用於我原來的帖子中討論的兩倍。我選擇了10以上來簡化一點。我應該能夠適應你所有給出的邏輯。

+1

不能幫助自己:http://xkcd.com/221/ – cwallenpoole

+1

聽起來像作業給我。 –

+0

我已合併您的未註冊帳戶。您現在應該能夠在答案下留下意見,編輯您的問題並最終接受幫助您的答案。請不要添加額外的答案作爲你的問題的更新,堆棧溢出不是一個論壇。 –

回答

0

我認爲,當你說「不重複」你的意思是「不同」(唯一的),而不是「最終變成定期」(如「PI不重複的數字」)

  1. 生成n您範圍內的不同整數。
  2. 從第5位挑選兩位。致電這些ab
  3. 刪除列表中的最後3個。
  4. 在子列表中的位置0,1,2或3處插入a
  5. 在子列表中的位置0,1,2,3或4插入b
  6. 將子列表添加回列表的末尾。

刪除子列表並不是必需的,但使其更容易概念化。

如果n + 2小於10,該怎麼辦並不明顯。特別是,該算法可能會崩潰,並返回n = 7的錯誤結果。

0

一定範圍內產生不同的號碼,你可以使用這樣的事情:

$arr_num = array(); 

while(count($arr_num)<=7) 
{ 
    $num = rand(1, 9); 
    if (!in_array($num, $arr_num)) 
    { 
    $arr_num[] = $num; 
    } 
} 

$ arr_num現在有8組不同的元素。挑陣列的五個要素:

for ($i=0; $i<=4; $i+=1) 
{ 
    $new_arr[$i] = $arr_num[$i]; 
} 

現在從$ new_arr號碼選兩個號碼:

$r1 = array_rand($new_arr); 
$r2 = array_rand($new_arr); 

現在你可以在兩個最後的隨機位置的插入這些數字到原來的數組。希望它有幫助!

+0

'$ arr_num'數組中的元素將是截然不同的,但它不太可能會是7. – deceze

+0

沒錯!我會修改它,以便它具有(n)不同的元素! –

+0

現在,循環有一個很小的機會,它永遠不會完成,至少它可能是非常昂貴的。 O(蘭特)對此是一個有效的大O符號嗎? ; -3 – deceze

0

如果我理解正確的話,你必須在10組排列與有關重複一些具體的標準來使用1到N個隨機數。在PHP中,我建議這個(不包括php內部)O(n)解決方案:

//Generate a full list of keys 
$source = range(1, MAX); 
//NOTE: if MAX < 10, you must pad the array 

//Get a random group of 10 of the keys 
$input = array_rand(array_flip($source), 10); 

//Shuffle (can be done later as well; this is the randomization). 
//array_rand() does not change order. 
shuffle($input); 

//Select the first of 5 that must be repeated in the last 5 
$one = rand(0, 4); 
$onev = $input[$one]; 

//Remove this array key to prevent collisions with the second of 5 
$input = array_diff($input, array($onev)); 

//Select a random index in the last 5 to be replaced with $one 
$rep = rand(5, 9); 
$repv = $input[$rep]; 

//Remove this array key to prevent collisions with the other to-be-replaced 
$input = array_diff($input, array($repv)); 

//Acquire the new keys list of input now that two elements have been removed 
$keys = array_slice(array_keys($input), 0, 3); 
//Select the second-of-5 to replace in the last 5. No worry of collision now. 
$two = array_rand($keys, 1); 
$two = $keys[$two]; 

//Select the second from the last-of-5 to be replaced by $two 
//No worry of collision because the other index is removed. 
$keys = array_slice(array_keys($input), 4, 8); 
$rept = array_rand($keys, 1); 
$rept = $keys[$rept]; 

//Replace one of the last-of-five with one of the first-of-five 
$input[$rept] = $input[$two]; 

//Restore removed keys as well as perform replacement of other last-of-five 
$input[$one] = $onev; 
$input[$rep] = $onev; 

//re-randomize based on shuffle 
ksort($input); 

沒有循環,沒有條件。

0
$max = 15; 

$array = array(1, $max); 
for($x = 1; $x <= $max; $x++) 
{ $array[$x] = rand(1, $max); } 

$firstDup = $array[rand(1,5)]; 
$secondDup = $firstDup; 
do { $firstDup = $array[rand(1,5)]; 
} while($firstDup == $secondDup); 

do { $array[rand($max-5,$max)] = $firstDup; 
} while(!in_array($firstDup,array_slice($array,$max-5,5))); 

do { $array[rand($max-5,$max)] = $secondDup; 
} while(!in_array($secondDup,array_slice($array,$max-5,5))); 
0

希望這可以讓你用自己的方式:

$max = 20; // max value 
$repeats = 2; // numbers to be repeated 

$nums = range(1, $max); 
shuffle($nums); 

$halfPoint = ceil($max/2); 
$firstHalf = array_slice($nums, 0, $halfPoint); 

$repeaters = array_intersect_key($firstHalf, array_flip(array_rand($firstHalf, $repeats))); 
$secondHalf = array_merge(array_slice($nums, $halfPoint), $repeaters); 
shuffle($secondHalf); 

$result = array_merge($firstHalf, $secondHalf); 

var_dump(join(',', $result)); 
0

一個對這個解決方案的警告詞。我不會將它用於一大組數字。如果我爲一個更大的集合做同樣的解決方案,我會使用array_splice從數組中刪除選定的成員。當你得到一個更大的空間時,在你的範圍內找到一個未使用的數字會變得相當昂貴,並且要求比下面的蠻力方法更好的解決方案。

這將構建一半的目標集。你會打兩次,每半打一次。

function build_half($min, $max, $num_elements, $arr = array()){ 

    while(count($arr) <= $num_elements) 
    { 
     $candidate = rand($min, $max); 
     if(!in_array($candidate, $arr)) 
     { 
      array_push($arr, $candidate); 
     } 
    } 
    return $arr; 
} 

這將從數組中抓取$ this_many元素。

function random_grab($arr, $this_many){  // don't try this on the subway 
    $nums_to_repeat = array(); 

    // catch some edge cases... 
    if($this_many > count($arr)) 
    { 
     return FALSE; 
    } 
    else if($this_many == count($arr)) 
    { 
     return shuffle($arr); 
    } 

    while(count($nums_to_repeat) <= $this_many) 
    { 
     $rand_key = rand(0, count($arr) - 1); 

     if(! in_array($arr[$rand_key], $nums_to_repeat)) 
     { 
      array_push($nums_to_repeat, $arr[$rand_key]); 
     } 
    } 
return $nums_to_repeat; 
} 

這是一個相當專業的情況,但可以通過允許偏移地板和天花板被作爲參數傳入變得更普遍。對於你的問題,他們會是5和9,所以我們直接派生它們。

function random_insert_2nd_half($target, $source){ 
    $offsets_consumed = array(); 
    $num_elements = count($target); 

    while(count($source) > 0) 
    { 
     $offset = rand(($num_elements/2), $num_elements - 1); 

     if(! in_array($offset, $offsets_consumed) 
     { 
      $arr[$offset] = array_pop($nums_to_repeat); 
     } 
    } 
} 

好了所以完成了所有這些之後,讓我們開始工作。

// Generate the first half of the array 
$my_array = $repeated_nums = array(); 
$my_array = build_half(1, 10, 5); 

// then grab the 2 random numbers from that first half. 
$repeated_nums = random_grab($my_array, 2); 

// So now we have our random numbers and can build the 2nd half of the array. 
// we'll just repeat the call to the first function. 
$my_array = build_half(1, 10, 5, $my_array); 

// Then swap out two of the values in the second half. 
$my_array = random_insert_2nd_half($my_array, $repeated_nums); 

// at this point $my_array should match what you are looking for.