校招算法篇之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的时候,每种方法的运行时间,



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