10萬個數字無序排列,要求不重複!高手進!!!

來源:互聯網
上載者:User
(PS:可能是我描述的不太清楚,其實意思就是這樣的。 依次產生10W個隨機數填充到數組, 隨機數1-10W之間不能重複。嗯,對,本意就是這樣。)

今天面試,技術總監給我出了個思考題,求隨機10W個數字無序排列,如何才能高效的執行,記憶體沒有要求,最好的硬體設定,虛擬碼如下:

static $arr = array();for($i = 0; $i < 100000; $i++){    $rand = rand(1,100000);    $y = 0;    while($rand == $arr[$y])    {        $rand = rand(1,100000);        $y++;    }    $arr[$i] = $rand;}

這樣做的壞處就是 剛開始取得第一個數的時候進入while迴圈的機率是1/100000,那麼當取到了第99999個數的時候,進入while迴圈的幾率就是99.9999%,那麼這時候就會出現無限迴圈狀態,那麼如何規避這個問題呢?

回複內容:

(PS:可能是我描述的不太清楚,其實意思就是這樣的。依次產生10W個隨機數填充到數組,隨機數1-10W之間不能重複。嗯,對,本意就是這樣。)

今天面試,技術總監給我出了個思考題,求隨機10W個數字無序排列,如何才能高效的執行,記憶體沒有要求,最好的硬體設定,虛擬碼如下:

static $arr = array();for($i = 0; $i < 100000; $i++){    $rand = rand(1,100000);    $y = 0;    while($rand == $arr[$y])    {        $rand = rand(1,100000);        $y++;    }    $arr[$i] = $rand;}

這樣做的壞處就是 剛開始取得第一個數的時候進入while迴圈的機率是1/100000,那麼當取到了第99999個數的時候,進入while迴圈的幾率就是99.9999%,那麼這時候就會出現無限迴圈狀態,那麼如何規避這個問題呢?

UPDATE:既然題主明確了題意,我這裡也更新下:

產生10W個數,範圍[1..10w]且無重複,那麼只需要先在長度為10W的數組內填上1..10W,然後用下面的演算法shuffle就行。

這個實際上可以通過Fisher-Yates shuffle演算法來實現,漸進複雜度可以達到O(n)。描述如下:

void randomize(vector& data) {    for (int i = data.size() - 1; i > 0; --i) {        int random = rand() % (i + 1);  // 所以 0 <= random <= i         swap(data[random], data[i]);    }}

要證明這個演算法的正確性也很簡單。但是需要將條件轉換成等價的形式,條件裡說我們需要對數組隨機排列,這意味著每個數出現在某個位子的幾率均等,均為1/n(假設有n個數)

我們考慮演算法執行第一次迴圈的時候:我們從[0,n-1]這n個數裡隨機挑選了一個數放到n-1這個位置,所以所有的數放到n-1的機率為1/n

當執行第二次的時候,我們從[0...n-2]這n-1個剩下的數裡選出了一個放到n-2這個位置,那麼出現在n-2位置的機率是多少呢?注意現在這件事並不是獨立事件了,一個數要放到n-2這裡意味著它沒有在第一次迭代中被選中,並且第二次被選中了,所以機率為(1-1/n)(1/(n-1)) = ((n-1)/n)(1(n-1)) = 1/n,故而所有數放在n-2的機率為1/n

一般的,一個數放在位置i時,意味著前面n-i-1次迴圈他都未被選中,且在第n-i次被選中,我們有機率p(i) = (1-1/n)(1-1/(n-1))(1-1/(n-2))....(1-1/(i+2))(1/(i+1) = ((n-1)/n) ((n-2)/(n-1)) ((n-3) / (n-2))...((i+1)/(n+2))(1/(i+1)) = 1/n

產生10W個數字,隨機遞增,再對結果集亂序

shuffle(range(0,100000));

步驟
1產生0-99999連續數組a
2空數組b
3隨機從a中取出一個放入b並從a中刪除該元素,直到取完

可以考慮使用 Format-preserving encryption

大致的目的就是格式不變的加密,在這個例子裡,可以把5位元加密成另一個5位元。

看到題目的第一個反應,真的只有我想到了C++的STL中的random_suffle函數麼……
後來仔細看了一下題主用的是PHP(為啥貼的是C標籤啊……)
好吧,我們來個簡化版的。
結果一看,dahakawang已經給出實現了,好吧,就由我改成PHP文法吧~

$a=array();for($i=0;$i<100000;$i++) $a[$i]=$i+1;for($i=99999;$i>=0;$i--){    $j=rand(0,$i);    $t=$a[$j];    $a[$j]=$a[$i];    $a[$i]=$t;}

直接手寫的,如有語法錯誤自行改正。

【隨機10W個數字無序排列】這其實沒說明問題...

如果解釋為【給10萬個隨機數做無序排列】,我覺得代碼只需要一行:return。

把10萬個數放在數組裡面,然後數組隨機順序就行了。好吧,我承認這麼搞根本符合題意。
下面的偽碼應該是期望的,不過貌似接近 @Dappur 的答案。

$arr=range(1, 100000, 1);//shuffle($arr); 哈哈,這是玩笑$results = [];for($i=99999;$i>=0;$i--){    $key=rand(0,$i);    $results[]=$arr[$i];    array_slice($arr, $i, 1);}

shuffle: 打亂數組順序。
range: 建立區間數組,參數分別是最小值、最大值、步長。
array_slice: 取出數組中的一段,並重設下標。

重新@Dappur
想明白你的代碼了...相當於10萬個人,每個人舉著一個號,然後喊一聲跑,自然就亂了。
而像樓主說的那種逐個產生(就是不事先預定好)除了他自己寫的那種方式外則是無解的,就像10萬人都是隔離的,自由說一個數,還不能和別人重複,不可能。

高效是指快麼?
如果是,我會順序產生10W個數,開10W個線程隨機插入,如果位置已經被佔用就用就近原則找位置插入。
如果有10W個核的應該挺快的

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.