數論初步之素數判斷
基本數論-素數判斷
一、暴力求解
1、一個共識
x = a*b且x = sqrt(x)*sqrt(x) => a==b==sqrt(x)或者a<sqrt(x) 且 b > sqrt(x),即要麽a==b要麽一個大於根號x一個小於根號x
且a = x/b,那麽我們只用判斷小於sqrt(x)的數是否可以整除x即可。
2、暴力求法(O(n^(2/3)))
bool isPrime(int x){ for(int i=2;i<=sqrt(x);i++){ if(x%i==0) return false;
void getPrime(int x){ for(int i=1;i<=x;i++){ if(isPrime(i)) cout<<i; } }
3、素數普通篩選(n*log(n))
思想:任何一個素x = 素數*一個數,那麽我們可以在找到一個素數的時候,再花n/i的時間去把現在可以確定不是素數的數給標記出來。
如:已知2是一個素數那麽:2,4,6,8,10,12...2*i都不是素數。
那麽時間復雜度為:n/2+n/3+n/5+......+n/p,p為小於n的素數那麽漸進時間復雜度為O(n*log(n))
void getPrime(int x,int* primes){ for(int i=2;i<=x;i++){ if(primes[i]==0){ for(int j=2;j*i<=x;j++) primes[j*i] = 1; } } }
4、素數篩選之線性篩選(o(n))
由3我們可以知道,任何一個數字都可以有一個素數乘一個數得到。比如2是素數那麽4,6,8,10,12,14,16....2*i都不是素數了,比如3是素數那麽6,9,12,15...3*i都不是素數了,我們
可以看出在我們標記不是素數的時候6,12等在2中標記過,在3中也被標記過這樣一來就多了很多重復的操作,那麽怎麽去優化呢?
我們最容易想到的就是在int j這個循環中加入,prime[j*i]!=1這個標誌,就可以很容易的跳過多余的標記,那麽我們總共標記了n個元素所以時間復雜度為O(N).
void getPrimeLine(int x,int* primes){ for(int i=2;i<=x;i++){ if(primes[i]==0){ for(int j=2;j*i<=x&&primes[j*i]!=1;j++) primes[j*i] = 1; } } }
或者我們可以根據當前的已知的素數來標記如已知 1,2,3,5現在第6次標記就用1,2,3,5分別乘2,3,4,5,6這樣每次乘出來的也不一樣最終也不會重復標記,因而時間復雜度為O(N)
數論初步之素數判斷