給定數字N,生成1,2,3...,N共N個不重複的隨機數


題目:

給定數字N,N>0, 設計一個隨機數生成器,運行該生成器N次,能夠不重複地生成1,2,..,N。


思路1:

最簡單的方法,首先定義一個隨機數生成器,其可以生成1-N範圍內的隨機數。     第一次運行時生成一個隨機數,然後記錄該隨機數已經生成過,例如,可以定義數組bool array[N]={false}, 第一次生成了x,則置array[x-1]=true; 第二次時,先生成一個隨機數,然後檢查是否已經了,如果是,則重新生成,直到生成一個沒有生成過的爲止。

缺點: 可能會花費很長時間,例如,前面千辛萬苦生成了N-1個數之後,最後需要生成一個剩餘的7,你可能運行1年也得不到這個7啊。 這是工程實踐中的大忌!!!!!


思路2:

面試時竟然想了出來,見的算法多了真是有用的。

考慮到思路1的缺點在於隨機數生成後有可能與前面的重複,於是着手解決該問題。

當時場景:有N個測試案例,請設計隨機數生成器,用於生成1-N數字,(得到這個數字後對應的測試案例會被運行),運行該生成器N次後,能夠覆蓋素有測試案例。

首先建立一個鏈表,共有N個節點(例如,每個節點對應要給測試案例,即用於隨機案例測試的場景)。第一次時,生成1-N範圍內的數字,例如生成了3,則把鏈表中的第三個節點刪除, 鏈表中還剩餘N-1個節點,然後,下一次可以控制生成器生成1-(N-1)範圍內的任意一個數,這樣就不會存在重複問題了。

但是,一個缺點是,每次刪除鏈表中的節點的時候,需要遍歷鏈表,導致時間複雜度爲o(n^2)。

 

查閱資料後,最優的解決辦法:

繼續保持我的這個思路,,第一次時生成1-N範圍的,第二次時生成1 - (N-1)範圍的,,,。然後,關鍵在於如何使用這些生成的數。因爲第一次和第二次生成的可能都是3。 下面數組登場, 先定義以數組base[N],base[i] = i+1,使得其保存1-N。

 

假設第一次時,產生3,則將3作爲一個索引值, 從base中得到base[3],(索引的話,隨機數生成器的範圍改成0  -- N-1),

然後,將base[3] = base[N-1],即將最後一個元素放到3的位置,因爲下一個隨機數生成的範圍爲0 - N-2,不會得到base[N-1]了,這樣也可以保證第二次同樣生成3時,能取到不同值呀。

另外,第一次生成N-1時,則取base[N-1],然後base[N-1] = base[N-1],也ok的。
 

Note小技巧: val = max*coeff, coeff=[0,1), max爲正整數,coeff爲float,, (int)val屬於[0,max-1],向下取整了。

 

Show me:

#include <iostream>
#include <vector>
#include <cstdlib>

/*
  Function:       generateRandomNums
  Description:    Give parameter N(N>0), then generate N unduplicated random numbers within the range from 1 to N.
*/
void generateRandomNums(unsigned int max)
{
	if (max < 1)
		return;
	unsigned int MaxNum = max;
	std::vector<unsigned int> BaseArray(max);
	std::vector<unsigned int> mResult(max);
	unsigned int si = BaseArray.size();
	for (unsigned int i = 0; i < max; ++i)
	{
		BaseArray[i] = i + 1;
	}

	for (int i = 0; i < MaxNum; ++i)
	{
		/**generate a random number within the range of max*[0,1)*/
		int index = (rand() % 100) / 100.0f *max;
		/**get a member from BaseArray*/
		mResult[i] = BaseArray[index];

		BaseArray[index] = BaseArray[max - 1];
		/**decrease max to ensure that mResult's elements is ununduplicated. */
		max--;
	}
	for (auto val : mResult)
	{
		std::cout << val << std::endl;
	}

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章