校招算法篇之N以內的素數

博客斷更了一段時間,現在準備重新撿起來。寫博客是一個總結,分享的過程,也是提升自我表達的很好的方式。將一個問題以深入淺出的方式表達出來,讓讀者讀的開心,容易理解,這是我們開發人員職業生涯當中很重要的一個能力。


前一陣子秋招,筆試面試了挺多公司,也積累了一點點自己的經驗,想陸續分享出來,也請各位多多斧正。


第一家面試的是深圳一家遊戲公司,手寫算法題,求N以內的素數,當然需要一步步的去優化時間複雜度,過程就不細說了,下面說說我的理解。

1、首先是最常規的解法,判斷n是不是素數,即判斷n能否被[2,sqrt(n)]整除,若一個數不是素數,那麼它分解的因數中一定有一個小於等於sqrt(n),另一個大於等於sqrt(n)。

	static List<Integer> prime1(int n) { //n>=2
		List<Integer> pri=new ArrayList<>();
		pri.add(2);
		for(int i=3;i<=n;i=i+2) {
			int tmp=(int)Math.sqrt(i);
			int j=2;
			for(;j<=tmp;j++) {
				if(i%j==0) break;
			}
			if(j>tmp) pri.add(i);
		}
		return pri;
	}


2、思考發現,判斷n能否被[2,sqrt(n)]整除,其中的除過2之外的偶數是多餘的,即只用判斷[2,sqrt(n)]之間的奇數。因爲n若不能被2整除,就一定不能被2之後的偶數整除,這樣可以減小判斷的時間。

	static List<Integer> prime2(int n){
		List<Integer> pri=new ArrayList<>();
		pri.add(2);
		for(int i=3;i<=n;i=i+2) {
			int tmp=(int)Math.sqrt(i);
			int j=3;           //i已限定奇數,對2求餘不爲0
			for(;j<=tmp;j=j+2) {
				if(i%j==0) break;
			}
			if(j>tmp) pri.add(i);
		}
		return pri;
	}


3、繼續探索,判斷n能否被[2,sqrt(n)]之間的奇數整除,這些奇數裏面的合數是多餘的。因爲任何一個合數都可以分解爲它前面若干個素數的積,若不能被它前面的素數整除,則亦不能被此合數整除。所以整除的範圍縮小爲[2,sqrt(n)]之間的素數。剛好本題目的目的就是求素數,所以可以將求得的素數放在數組內用來判斷。

	static List<Integer> prime3(int n) {
		List<Integer> pri=new ArrayList<>();
		pri.add(2);
		boolean flag=true;
		for(int i=3;i<=n;i=i+2) {
			flag=true;
			int tmp=(int)Math.sqrt(i);
			for(int j=0;j<pri.size() && pri.get(j)<=tmp;j++) {
					if(i%pri.get(j)==0) {
						flag=false;
						break;
					}
			}
			if(flag) pri.add(i);
		}
		return pri;
	}

4、因爲Java的ArrayList的get和add函數比起數組的存取來講是比較耗時的,考慮是否可以使用數組代替List。如要用數組代替List,首要考慮問題開闢多大的數組比較好,在儘量節省內存的情況下可以使用素數定理。n以內素數的數量大約是n/ln(n),這個估計是小於真實值的,所以在實際使用的時候需要視情況再加幾個。若n=2000000,此處選擇數組大小是n/10。

	static int[] prime4(int n) {
		int num=n/10;
		int[] pri=new int[num];
		pri[0]=2;
		int k=1;
		boolean flag=true;
		for(int i=3;i<=n;i=i+2) {
			flag=true;
			int tmp=(int)Math.sqrt(i);
			for(int j=0;j<num && pri[j]>0 && pri[j]<=tmp;j++) {
				if(i%pri[j]==0) {
					flag=false;
					break;
				}
			}
			if(flag) {
				pri[k]=i;
				k++;
			}
		}
		return pri;
	}


機器配置,


在n=2000000的時候,每種方法的運行時間,



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