【面试题】面试题合集三

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!以后的阶乘对结果不起任何影响,这样能够大大下降计算量了。

相关文章
相关标签/搜索