常見演算法題
阿新 • • 發佈:2018-11-02
1.用簡單素數篩選法求N以內的素數。
void printPrime()
{
int n;
scanf("%d",&n);
int i,j;
for(i=2;i<=n;i++) //遍歷2~N的所有數
{
for(j=2;j<=i;j++)
{
if(i%j==0&&i!=j) //不是素數,跳出迴圈
break;
if(i%j==0&&i==j)
printf("%d\n",i);
}
}
}
2.使用位操作壓縮後的篩素數方法
#include <stdio.h> #include <memory.h> int getPrime(int primes[],int max) { int i,j,n; int flag[max/32+1]; n=0; memset(flag,0,sizeof(flag)); for(i=2;i<max;i++) if(!( (flag[i/32]>>(i%32))&1 ))//判斷指定位上是0還是1 { primes[n++]=i; for(j=i;j<max;j +=i) flag[j/32] |=(1<<(j%32));//在指定位上置1 } return n; } void PrintfArray(int primes[],int n) { for(int i=0;i<n;i++) printf("%d ",primes[i]); putchar('\n'); } int main() { int i=1000; int primes[i/3+1]={0}; int n=getPrime(primes,i); PrintfArray(primes,n); }
3.陣列中除了兩個數字外,其它數字都出現了2次,找出這兩個數字。
void FindTwoNotRepeatNumberInArray(int *a, int n, int *pN1, int *pN2) { int i, j, temp; //計算這兩個數的異或結果 temp = 0; for (i = 0; i < n; i++) temp ^= a[i]; // 找第一個為1的位 for (j = 0; j < sizeof(int) * 8; j++) if (((temp >> j) & 1) == 1) break; // 第j位為1,說明這兩個數字在第j位上是不相同的 // 由此分組即可 *pN1 = 0, *pN2 = 0; for (i = 0; i < n; i++) if (((a[i] >> j) & 1) == 0) *pN1 ^= a[i]; else *pN2 ^= a[i]; }
4.給定一個包含n個整數的陣列,除了一個數出現一次外,所有整數均出現三次,找出這個只出現一次的整數.
思路:對於出現3次的整數,它的二進位制每一位1出現的次數都是3次。將該位置為0,剩下的就是出現1次的數。
int singleNumber(int a[],int n) { int ones=0; //二進位制1出現奇數次的位 int twos=0; //二進位制1出現偶數次的位 int threes=0; //用來處理二進位制1出現三次的位 for(int i=0;i<n;i++) { twos |=(ones&a[i]); //ones&a[i] 遍歷到當前變數為止 二進位制1出現偶數次的位 //將結果與twos異或 統計所有二進位制1出現偶數次的位 ones ^=a[i]; //將ones異或當前元素,結果為二進位制1出現奇數次的位 threes =~(ones&twos); //ones&twos 若某位為1,說明出現3次,取反 清除出現3次的位 twos &=threes; //清除twos中出現3次的位 ones &=threes; //清除ones中出現3次的位 } return ones; }
5.快速冪 假設我們要求a^b,那麼其實b是可以拆成二進位制的,該二進位制數第i位的權為2^(i-1),因此可以將a¹¹轉化為算 a2^0*a2^1*a2^3,也就是a1*a2*a8
int pow(int a,int b)
{
int ans=1,base=a;
while(b!=0)
{
if(b&1 !=0) //最後一位為1
ans *=base;
base *=base;
b>>=1;
}
return ans;
}
6.輸入一個整數n,求從1到n這n個整數的十進位制表示中1出現的次數。例如輸入12,從1到12這些整數中包含1的數字有1,10,11和12,1一共出現了5次。
從一個5位的數字舉例分析,先考慮其百位為1的情況。分3中情況討論(方便起見,計前三位為a,後兩位為b)
- 百位數字取2~9,example:33298 易知後兩位的取值範圍為00~99,,共10*10=100種情況。a的前兩位的取值為00~a/10,所以共有(a/10+1)*100,即3400種情況
- 百位數字==1, example:33198 易知前兩位的取值範圍為0~33,但當前三位固定為331時,後兩位只能取0~98,所以共有(a/10+1-1)*100+b+1
- 百位數字==0 example:33098 注意相比較第一種情況少了100次,易知取值範圍為(a/10)*100
進一步統一百位數不為1的表示式(即百位數>=2或者==0):((a+8)/10)*100
加8的原因:百位數大於等於2時,加8產生進位,此時(a+8)/10的值等於a/10+1的值,舉例:a=332時,a+8=340,340/10=34.而332/10+1=34
有了以上的分析,就可以很容易的寫出求去1~N中各個位上1出現的次數之和的程式碼
int NumberOf1Between1AndN(int n)
{
int count = 0;
int a,b;
for (long i = 1; i <= n; i *= 10)
{
a = n / i;
b = n % i;
count += (a + 8) / 10 * i + ((a % 10 == 1) ? b + 1 : 0);
}
return count;
}