【面試題】面試題合集三

1.【百度】給定一個無序數組,其中有一個元素個數超過數組元素個數的一半,請找出該元素,要求時間複雜度爲O(n),空間複雜度爲O(1)。面試

2.【360】給定一個無序數組,尋找第k大的元素,要求時間複雜度爲O(n)。數組

3.【XX】給定一個含有2*k+1個元素的無序數組,其中有k個元素出現兩次,有1個元素出現一次,請找出該元素,要求時間複雜度爲O(n)。ui

4.【XX】給定一個含有2*k+2個元素的無序數組,其中有k個元素出現兩次,有2個元素出現一次,請找出該元素,要求時間複雜度爲O(n)。spa

5.【XX】給定一個含有4*k+2個元素的無序數組,其中有k個元素出現,有1個元素出現兩次,請找出該元素,要求時間複雜度爲O(n)。
code

6.【XX】給定兩個無序數組X[m],Y[n],求兩個數組按遞增形式合併後,位於中間的元素,要求時間複雜度爲O(n)。blog

7.【羣碩】編寫一個程序判斷一個數是不是迴文素數(迴文素數就是從左向右讀與從右向左讀徹底同樣的素數,好比11,101,131,151,313,...)遞歸

分析:主要是迴文的判斷,是否素數是很好判斷的。ip

判斷迴文,最簡單就是將數字翻轉過來,而後判斷是否相等便可。io

#include <stdio.h>
#include <stdlib.h>

int is_sushu(int val){
	int k;

	if(val<0||val%2==0)
		return -1;
	if(val==1||val==2)
		return 0;
	for(k=3; k<val/2; k+=2)
		if(val%k==0)
			return -1;
	return 0;
}

int is_huiwen(int val){
	int temp=val;
	int k=0;
	while(temp){
		k=k*10+temp%10;
		temp = temp/10;
	}
	if(k==val)
		return 0;
	else
		return -1;
}

int main(void){
	int val;

	scanf("%d", &val);
	if(is_sushu(val)==0&&is_huiwen(val)==0)
		printf("%d is a huiwensushu\n", val);
	else
		printf("%d is not a huiwensushu\n", val);

	system("pause");
	return 0;
}

8.【羣碩】輸入兩個整數n和m,從數列1,2,3,...,n中隨意取幾個數,使其和等於m,要求將其中全部的可能組合列出來。class

題目木有說明是否能夠重複取值,但假設能夠取重複數,可知最多能夠取m個數,m*1=m嘛,範圍爲[1, ∞)若是不可取重複數,那麼,至少須要取k個數((1+k)*k/2≥m),而最大值則爲(n+1)*n/2,因此取值範圍爲[1, (n+1)*n/2]。

①能夠取重複數

那麼最多有m層遞歸,但層數不肯定,沒法用循環,因此仍是用遞歸裏面的回溯法吧。

只要保證下一層遞歸取值爲≥上一層遞歸的取值,則能夠確保結果的不重複性,由於最多能夠取m個數,那麼分配m個存儲空間保存結果便可。

find_two表示從1,...,n中取兩個數a,b使得a+b=m,

那麼當取定a=k時,再從1,...,n中尋找兩個數a',b'使得a'+b'=m-k便可,這樣就成爲子問題了。

遞歸的結束條件則爲當求和的值m<=0則直接結束,若是m≤n時,還能夠找到一個數的狀況,因此不要遺漏便可。

#include <stdio.h>
#include <stdlib.h>

static int *num;
static int len;
void find_two(int m, int n, int s){
	int k;

	if(m<=0)
		return;
	if(m<=n&&m>=s){
		for(k=0; k<len; k++){
			printf("%d ", *(num+k));
		}
		printf("%d", m);
		printf("\n");
	}
	for(k=s; k<=n; k++){
		if(k>m)
			break;
		*(num+len++)=k;
		find_two(m-k, n, k);
		len--;
	}
}

int main(void){
	int m,n;

	scanf("%d", &n);
	scanf("%d", &m);
	num = (int*)calloc(m, sizeof(int));
	len = 0;

	find_two(m, n, 1);
	system("pause");
	return 0;
}

②不可取重複數(原理與①類似,在①的代碼上稍做修改便可)

#include <stdio.h>
#include <stdlib.h>

static int *num;
static int len;
void find_two(int m, int n, int s){
	int k;

	if(m<=0)
		return;
	if(m<=n&&m>s){
		for(k=0; k<len; k++){
			printf("%d ", *(num+k));
		}
		printf("%d", m);
		printf("\n");
	}
	for(k=s+1; k<=n; k++){
		if(k>m)
			break;
		*(num+len++)=k;
		find_two(m-k, n, k);
		len--;
	}
}

int main(void){
	int m,n;

	scanf("%d", &n);
	scanf("%d", &m);
	num = (int*)calloc(m, sizeof(int));
	len = 0;

	find_two(m, n, 0);
	system("pause");
	return 0;
}

另外一種代碼風格:

依然是遞歸方法,對於當前求和值爲sum,先取值k,剩餘sum+k,若sum+k>m,則無需再取,直接退回上層;若sum+k<m,則繼續取值(爲避免重複,取值須要大於k,即從k+1開始取);若sum+k==m則打印結果。這種風格略顯麻煩。

#include <stdio.h>
#include <stdlib.h>

static int *num;
void dis_zuhe(int s, int sum, int m, int n){
	//s上一層取值,此層取值由s+1開始
	int k;

	if(sum==m){
		for(k=0; k<n; k++){
			if(*(num+k))
				printf("%d ", k+1);
		}
		printf("\n");
	}
	else{
		for(k=s+1; k<=n; k++){
			sum+=k;
			*(num+k-1)=1;
			if(sum>m){
				sum-=k;
				*(num+k-1)=0;
				break;
			}
			dis_zuhe(k, sum, m, n);
			sum-=k;
			*(num+k-1)=0;
		}
	}
}

void find(int n, int m){
	int summax;
	int sum=0;
	summax = (n+1)*n/2; //don't care about overflow
	if(summax<m)
		return;
	dis_zuhe(0, sum, m, n);
}

int main(void){
	int m,n;

	scanf("%d", &n);
	scanf("%d", &m);
	num = (int*)calloc(n, sizeof(int));
	find(n, m);

	system("pause");
	return 0;
}

9.【聯發科】有10盒藥,每盒有56顆藥片,其中有一盒藥片由於過時而致使吸取空氣水分使得每顆藥片增長了1g,如今有一個電子天平,並且能夠準確讀出兩邊相差重量(準確到g),如何只使用一次天平找出那盒過時的藥?

分析:

爲了區分每盒藥,那麼分別從第一盒到第九盒藥中取出1,2,3,4,...,9顆藥片,第十盒藥則取出前面9盒取出的藥片數之和(即45顆);

前9盒藥放在天平左邊,第十盒放在天平右邊;

若是第一盒過時,則左邊天平必比右邊天平重1g;若是第i盒(i∈[1,9])過時,則左邊天平比右邊天平重ig;若是第10盒過時,則右邊天平更爲重些。

10. 【XX】求階乘之和S=1!+2!+...+n!的結果末尾6位數,n範圍爲2≤n≤100000

分析:

安裝常規循環計算,除了要解決溢出翻轉問題還須要考慮效率的問題。

此題爲求解n!末尾0的位數的變種題,當p!末尾有6個0時,任意m>p,m!末尾均有6個0,由於m!=p!*(p+1)*...*m,所以先找出末尾6個0首次出現的階乘便可。

由以前的面試題能夠得知,末尾有6個0時,將恰好有6個因子5,那麼包含這6個因子5的數分別爲五、十、1五、20、25(5*5有兩個5),因此25!以後的階乘對結果不起任何影響,這樣能夠大大下降計算量了。

相關文章
相關標籤/搜索