十月份第三周笔试题

这一周比较杂,笔试了网宿科技,上海先锋商泰,然后周四晚上面试了网宿科技,上来就出了道挺变态的求最大子矩阵和的题。

【上海先锋商泰】

笔试都是选择题,除开前面的基础题,后面个个都是完整的给程序进行“完型填空”,记得有道题是树和森林的构造和遍历、简单的四则混合(包括括号)的计算器、给不同区域的着色问题。

今天早上跑过去面试,老实说,上午的状态一般都烂的一笔,就随便出了道算法题让我做,大致的题意如下:

假如有一个很大的bit流,比如“10000100011100010010101...”,让你给出个算法统计bit流中的1的个数。

这个问题实际上可也转化成“统计一个Byte中"1”的个数”,或者可以参考这个哥们的做法,点这里

【网宿科技】

网宿科技的笔试题大都是之前比较有名的一些笔试题,在网上大都可以搜到,不过第一题感觉挺容易让人糊涂的:

1、输出下列程序的结果,并进行相关的解释

#include<stdio.h>
int main()
{
	char *str[]={"Welcome","To","Chinanet","Center"};
	char **p=str+1;//p指向"To"的指针的指针
	str[0]=(*p++)+2;//将"To"字符串的第3个字符的地址赋给str[0]
	str[1]=*(p+1);//p指向"Chinanet"的指针的指针,将"Center"的地址赋给str[1]
	str[2]=p[1]+3;//p[1]等价于*(p+1),即将"Center"字符串中的第3个字符地址赋给str[2]
	str[3]=*(*(&str+1)-1)+1;//即将下一个指向该类str的指针解引用,
	//减1得到"Center"的地址,解引用加1得到"enter"的地址赋给str[3]

printf("%s\n",str[0]);
printf("%s\n",str[1]);
printf("%s\n",str[2]);
printf("%s\n",str[3]);
getchar();
}

相应的在win7上运行vs2012得到如下结果:


2、1)设计一个宏 ISUNSIGNED_VAR(a):判断一个数是否是有符号数还是无符号数

      2)设计一个宏ISUNSIGNED_TYPE(type):判断一个类型是有符号类型还是无符号类型

参考在《C专家编程》中的一个解决方案:

 

#define ISUNSIGNED_VAR(a) (a>=0 && ~a>=0)
#define ISUNSIGNED_TYPE(type) ((type)0-1>0)


当然,免不了要测试一下上面两个宏的可行性:

#include<stdio.h>
int main(void)
{
	unsigned int a=1;
	printf("variable \"a\" %s unsigned\n",ISUNSIGNED_VAR(a) ? "is":"isn't");
	printf("type \"unsigned int\" %s unsigned\n",ISUNSIGNED_TYPE(unsigned int) ? "is":"isn't");
	getchar();
	return 0;
}


得到如下的运行结果:

事实上,对 unsigned char类型,上述宏会存在问题:具体可以参看:http://www.cnblogs.com/xkfz007/archive/2012/03/27/2420172.html

3、判断一个单向链表中是否存在循环。

这貌似是一道微软的笔试题,网上大致的思路是说用两个指针(一个快指针,一个慢指针)来遍历链表,如果两个指针能同时访问同一个结点就说明该单向链表中存在循环!

具体的代码实现如下:

typedef struct Node{
	int data;
	struct Node* next;
}Node,*List;

#include<stdlib.h>
bool isCircle(List L){
	if(L==NULL || L->next==NULL)
		return false;  //链表为空,或者没有自环
	if(L->next==L)
		return true;   //链表有自环
	List pSlow=L;//每次一步
	List pFast=L->next;//每次两步
	for(;pSlow!=NULL && pFast!=NULL; pSlow=pSlow->next,pFast=pFast->next->next)
		 if(pSlow==pFast) return true; // 慢指针追上了快指针
	return false; //存在结点的next指针为NULL,即不存在环

}


4、实现strstr函数:

函数原型:extern char* strstr(char* str1,char *str2)
功能:找出str2字符串在str1字符串中第一次出现的位置
返回值:返回该位置的指针,如找不到,返回空指针

这应该算是一道非常常规的字符串处理的笔试题,我的一种实现如下:

char *strstr1(char *str1,char *str2)
{
	char *p,*q,*r;
	if(!str1||!str2) return NULL;
	for(p=str1;*p;p++){
		for(q=str2,r=p;*r && *q;r++,q++)
			if(*r!=*q) break;
		if(*q==0) return p;
		else if(*r==0) return NULL;
	}
	return NULL;
}

简单测试一下:

#include<stdio.h>
void main(){
char str1[]="my world!";
char str2[]="orl";
char * pos;
if((pos=strstr1(str1,str2))!=NULL)
    printf("%s\n",pos);
else
	printf("not found");

system("pause");

}


得到如下预期的运行结果:


之前看过一个相当NB的版本,摘录如下:

char* strstr(char* haystack,char* needle){
	for(;;++haystack){
		char* h=haystack;
		for(char*n=needle;;++n,++h){
			if(!*n) return haystack;
			if(*h!=*n) break;
		}
	if(!*h) return NULL;
	}
}


这里头还有个典故啊(干草堆中找针!)

 

5、输入一个整形数组,数组里有正数也有负数。编写程序,求出数组中连续多个数之和的最大值。要求时间复杂度为O(n)

//最大子序列和

int sum(int a[],int n){
//传入参数:数组地址和元素个数
	int max=0,temp=0;
	for(int i=0;i<n;i++){
		temp+=a[i];
		if(temp>max)
			max=temp;
		else if(temp<0)
			temp=0;
	}
	return max;
}
#include<stdio.h>
#include<stdlib.h>
void main(){
	int a[10]={-2, 11, -4, 13, -5, 2, -5, -3, 12, -9};
	printf("最大子序列和为:%d\n",sum(a,10));
	system("pause");
}


晚上面试的时候,网宿科技的面试官又给我出了一道和题4类似的题,只不过问题的主体已经换成了二维矩阵!

6、问题描述:给定一个M*N(0<M,N<=100)的矩阵,请找到此矩阵的一个子矩阵,并且此子矩阵的各个元素的和最大,输出这个最大的值。

Example:

0 -2 -7 0

9  2 -6 2

-4 1 -4 1

-1 8 0 -2

其中左上角的子矩阵:

9  2

-4 1

-1 8

此子矩阵的值为9+2+(-4)+1+(-1)+8=15

 

看吧,这与问题5是何其的像啊,只不过把一维的最大子段和换成了二维的最大子矩阵和,解决的方法实质应该还是一样的。

假设最大子矩阵的结果为从第r行到第k行,从第i列到j列的子矩阵,如下所示(假定数组各维下标都从1开始)

|a11 ... ... a1i ... ... a1j ... ... a1n|

|a21 ... ... a2i ... ... a2j ... ... a2n|

|   .       .       .       .      .      .      .   |

|   .       .       .       .      .      .      .   |

|ar1 ... ...  ari  ... .... arj ...... arn  |
|  .       .       .       .      .      .      .    |

|  .       .       .       .      .      .      .    |

|ak1 ... ... aki ... ... akj ... ...akn |

|  .      .       .        .     .      .      .    |

|am1 ... ... ami ... ... amj ... ... amn|

那么,将从第r行到第k行的每一行中相同列加起来,可以得到一个一维数组如下:

(ar1+... ...+ak1, ar2+... ...+ak2, ... ..., arn+ ... ...+akn)

由此,我们可以将该问题转换成求该一维数组的最大子段和的问题了。

我给出的实现代码如下:

//求最大子矩阵和
int Max_in_Row(int a[],int n,int *begin, int *end){
//传入参数:数组首地址,数组元素个数
//传出参数:最大子序列的区间[begin,end]
	int max=0,temp=0;
	*begin=0,*end=0;
	for(int i=0;i<n;i++){
		temp+=a[i];
		if(temp>max){
			*end=i;
			max=temp;
		}
		else if(temp<0){
			temp=0;
			*begin=i+1;
		}
	}
	
	return max;
}

#define M 4
#define N 4
int MatrixCompressToRows(int a[M][N],int *rbegin,int *rend,int *cbegin,int *cend){
	//输入参数:矩阵地址与行数M、列数N
	//输出参数:最大子矩阵和开始与结束的行号列号
	//打印出最大子矩阵及其和
	int i,j,k;
	int max=0,temp,temp1,temp2;
	*rbegin=0,*rend=0,*cbegin=0,*cend=0;
	int b[N];//将矩阵压缩成行,其每个元素保存从第i行开始到j行对应列的和
	//memset(b,0,N);

	for(i=0;i<M;i++){
		for(k=0;k<N;k++) //b[k]的值在i循环中置零
			 b[k]=0;
		for(j=i;j<M;j++){ //从第i行到第j行
			for(k=0;k<N;k++)
				b[k]+=a[j][k];//b[k]的值不用重新计算,只需每轮更新
			temp=Max_in_Row(b,N,&temp1,&temp2);
			if(temp>max){
				max=temp;
				*rbegin=i,*rend=j,*cbegin=temp1,*cend=temp2;
			}
		}
	}
	return max;
}

#include<stdlib.h>
#include<stdio.h>
void main(){
	int a[M][N];
	int rbegin,rend,cbegin,cend;
	printf("请按行序输入矩阵a[%d][%d]中的各元素值:", M,N);
	for(int i=0;i<M;i++)
		for(int j=0;j<N;j++)
			scanf("%d",&a[i][j]);

	printf("最大子矩阵和为:%d\n",MatrixCompressToRows(a,&rbegin,&rend,&cbegin,&cend));
	printf("最大子矩阵打印如下:\n");
	for(int i=rbegin;i<=rend;i++){
		for(int j=cbegin;j<=cend;j++)
			printf("%d\t",a[i][j]);
		printf("\n");
	}
	system("pause");
}

测试运行,得到如下的结果:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值