随机洗牌
問題:給定一個(gè)有序序列1~n,要你將其完全打亂,要求每個(gè)元素在任何一個(gè)位置出現(xiàn)的概率均為1/n。
解決方案:依次遍歷數(shù)組,對(duì)第n個(gè)元素,以1/n的概率與前n個(gè)元素中的某個(gè)元素互換位置,最后生成的序列即滿足要求,1/n的概率可通過rand() % n實(shí)現(xiàn)。見如下程序:
void swap(int* p, int* q)
{
????int tmp = *p;
????*p = *q;
????*q = tmp;
}
?
void shuffle(int *arr, int n)
{
????int i;
????for(i = 0; i < n; i++) {
????????int idx = rand() % (i + 1); //選取互換的位置
????????swap(&arr[idx], &arr[i]);
????}
}
?
?使用數(shù)學(xué)歸納法證明:
l??當(dāng)n=1時(shí),idx必為0,所以元素arr[0]在任何一個(gè)位置的概率為1/1,命題成立。
l??假設(shè)當(dāng)n=k時(shí),命題成立,即n=k時(shí),原數(shù)組中任何一個(gè)元素在任何一個(gè)位置的概率為1/k。
?則當(dāng)n=k+1時(shí),當(dāng)算法執(zhí)行完k次時(shí),前k個(gè)元素在前k個(gè)位置的概率均為1/k。
?當(dāng)執(zhí)行最后一步時(shí),前k個(gè)元素中任何一個(gè)元素被替換到第k+1位置的概率為:(1-1/(k+1)) * 1/k = 1/(k+1);?在前面k個(gè)位置任何一個(gè)位置的概率為(1-1/(k+1)) * 1/k = 1/(k+1);
故前k個(gè)元素在任意位置的的概率都為1/(k+1)
?所以,對(duì)于前k個(gè)元素,它們?cè)趉+1的位置上概率為1/(k+1)。
?對(duì)于第k+1個(gè)元素,其在原位置的概率為1/k+1,在前k個(gè)位置任何一個(gè)位置的概率為:(1-k/(k+1))?* (1/k)=1/(k+1),所以對(duì)于第k+1個(gè)元素,其在整個(gè)數(shù)組前k+1個(gè)位置上的概率也均為1/k+1。
?綜上所述,對(duì)于任意n,只要按照方案中的方法,即可滿足每個(gè)元素在任何一個(gè)位置出現(xiàn)的概率均為1/n。
?
擴(kuò)展:一道google面試題
給定一個(gè)未知長度的整數(shù)流(數(shù)目大于1000),如何從中隨機(jī)選取1000個(gè)隨機(jī)數(shù)。
?
解決方法:
l??定義長度為1000的數(shù)組,對(duì)于數(shù)據(jù)流中的前1000個(gè)關(guān)鍵字,顯然都要放到數(shù)組中。
l??對(duì)于數(shù)據(jù)流中的的第n(n>1000)個(gè)關(guān)鍵字,則這個(gè)關(guān)鍵字被隨機(jī)選中的概率為?1000/n。故以?1000/n?的概率用這個(gè)關(guān)鍵字去替換數(shù)組中的一個(gè)。這樣就可以保證所有關(guān)鍵字都以?1000/n的概率被選中。對(duì)于后面的關(guān)鍵字都進(jìn)行這樣的處理,這樣就可以保證數(shù)組中總是保存著1000個(gè)隨機(jī)關(guān)鍵字。
?
注:以1000/n的概率選擇一個(gè)數(shù)替換,可通過rand() % n實(shí)現(xiàn),則這個(gè)數(shù)被替換到前1000個(gè)位置中的概率為1000/n。
轉(zhuǎn)自:http://blog.chinaunix.net/uid-20196318-id-216658.html
轉(zhuǎn)載于:https://www.cnblogs.com/freeopen/p/5482894.html
總結(jié)
- 上一篇: HTML5 input元素新的特性
- 下一篇: java(13)内部类