careercup 高等難度 18 2

2021-09-22 19:12:29 字數 2328 閱讀 5393

18.2 編寫乙個方法,洗一副牌。要求做到完美洗牌,換言之,這幅牌52!種排列組合出現的概率相同。假設給定乙個完美的隨機發生器。

解法:假定有個陣列,含有n個元素,類似如下:

[1][2][3][4][5]

利用簡單構造法,我們不妨先問自己,假定有個方法shuffle(...)對n-1個元素有效,我們可以用它來打亂n個元素的次序嗎?當然可以,而且非常容易實現。我們會先打亂前n-1個元素的次序,然後,取出第n個元素,將它和陣列中的元素隨機交換。就這麼簡單!遞迴解法的演算法如下:

//

lower和highter(含)之間的隨機數

int rand(int lower,int

highter)

void shufflearrayrecursively(int cards,int

i)

以迭代方式實現的話,這個演算法又會是什麼樣?讓我們先考慮,我們要做的是遍歷整個陣列,對每個元素i,將array[i]與0到i(含)之間的隨機數交換。

void sufflearrayinteratively(int

cards,n)

}

洗牌問題(shuffle)就如隨機取樣(random sample)問題,在《計算機程式設計藝術》(volume 2 chapter 3)中得到了詳細的講解,關於該問題的詳細**可以翻閱該書相應章節。

洗牌問題,顧名思義,就是給你一把牌,讓你把它完全打亂,這可以歸結成乙個陣列問題:

給你乙個長度為n的陣列,要求你將其完全打亂,陣列中元素交換跟下標是一一對應的,所以也就可以表述為給你乙個有序序列0—n-1,要你將其完全打亂,要求每個元素在任何乙個位置出現的概率均為1/n。

洗牌問題是打亂乙個有序序列(比如下標有序)的演算法與隨機取樣頗有淵源,演算法也與隨機取樣問題十分相近,如下:

void shuffle(t* arr, int len)

for(int i=0; iint idx=rand()%(i+1);

swap(arr[idx], arr[i]);

演算法正確性證明也可以用數學歸納法證明:

待證明問題:對於乙個長度為n的陣列,經過上述演算法處理後,會得到乙個隨機數組,原陣列中每乙個元素在任何乙個位置的概率均為1/n

證明:演算法可以分為兩部分:前n-1次執行+最後一次執行

1、當n=1時,idx必為0,所以元素arr[0]在任何乙個位置的概率為1/1,命題成立。

2、假設當n=k時,命題成立,即n=k時,原陣列中任何乙個元素在任何乙個位置的概率為1/k。

當n=k+1時,當演算法執行完k次時,前k個元素在前k個位置的概率均為1/k,執行最後一步時,前k個元素中任何乙個元素被替換到第k+1位置的概率:

(1-(1/k)*(k/k+1)) * (1/k) = 1/k+1

所以,對於前k個元素,它們在k+1的位置上概率為1/k+1,在前面k個位置任何乙個位置上的概率為(1-1/(k+1)) * (1/k)=1/(k+1),對於前k個元素,其在整個陣列前k+1個位置上的概率均為1/k+1,

對於第k+1個元素,其在原位置的概率為1-(k/k+1)=1/k+1,在前k個位置任何乙個位置的概率為:(k/k+1) * (1/k)=1/k+1,所以對於第k+1個元素,其在整個陣列前k+1個位置上的概率也均為1/k+1。

命題得證。

能讓我理解的隨機洗牌問題。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

問題描述:假設有乙個陣列,包含n個元素。現在要重新排列這些元素,要求每個元素被放到任何乙個位置的概率都相等(即1/n),並且直接在陣列上重排(in place),不要生成新的陣列。用o(n) 時間、o(1)輔助空間。

演算法是非常簡單了,當然在給出演算法的同時,我們也要證明概率滿足題目要求。

先想想如果可以開闢另外一塊長度為n的輔助空間時該怎麼處理,顯然只要對n個元素做n次(不放回的)隨機抽取就可以了。先從n個元素中任選乙個,放入新空間的第乙個位置,然後再從剩下的n-1個元素中任選乙個,放入第二個位置,依此類推。

按照同樣的方法,但這次不開闢新的儲存空間。第一次被選中的元素就要放入這個陣列的第乙個位置,但這個位置原來已經有別的(也可能就是這個)元素了,這時候只要把原來的元素跟被選中的元素互換一下就可以了。很容易就避免了輔助空間。

我們先假設乙個5維陣列:1,2,3,4,5。如果第1次隨機取到的數是4, 那麼我們希望參與第2次隨機選取的只有1,2,3,5。既然4已經不用, 我們可以把它和1交換,第2次就只需要從後面4位(2,3,1,5)中隨機選取即可。同理, 第2次隨機選取的元素和陣列中第2個元素交換,然後再從後面3個元素中隨機選取元素, 依次類推。

c++實現:

void randomshuffle(int a, int

n)

careercup 高等難度 18 5

18.5 有個內含單詞的超大文字檔案,給定任意兩個單詞,找出在這個檔案中這兩個單詞的最短距離 也即相隔幾個單詞 有辦法在o 1 時間裡完成搜尋操作嗎?解法的空間複雜度如何?解法1 我們假設單詞word1和word2誰在前誰在後無關緊要。要解決此題,我們需要遍歷一次這個檔案。在遍歷期間,我們會記下最後...

careercup 高等難度 18 6

18.6 設計乙個演算法,給定10億個數字,找出最小的100萬個數字。假定計算機記憶體足以容納全部10億個數字。解法 方法1 排序 按公升序排序所有的元素,然後取出前100萬個數,時間複雜度為o nlog n 方法2 大頂堆 我們可以使用大頂堆來解題。首先,為前100萬個數字建立乙個大頂堆 然後,遍...

careercup 中等難度 17 7

17.7 給定乙個整數,列印該整數的英文描述 例如 one thousand,two hundred thirty four 解法 舉個例子,在轉換19 323 984時,我們可以考慮分段處理,沒三位轉換一次,並在適當的地方插入 thousand 千 和 million 百萬 也即,convert ...