1. 程式人生 > >常見演算法題

常見演算法題

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; 
}