0
点赞
收藏
分享

微信扫一扫

微软十五道面试题 答案


一、微软十五道面试题

1、有一个整数数组,请求出两两之差绝对值最小的值,
记住,只要得出最小值即可,不需要求出是哪两个数。

2、写一个函数,检查字符是否是整数,如果是,返回其整数值。
(或者:怎样只用 4 行代码编写出一个从字符串到长整形的函数?) 

3、给出一个函数来输出一个字符串的所有排列。

4、( a)请编写实现 malloc()内存分配函数功能一样的代码。

(b) 给出一个函数来复制两个字符串 A 和 B。字符串 A 的后几个字节和字符串 B 的前几个
字节重叠。 

5、怎样编写一个程序,把一个有序整数数组放到二叉树中? 

6、怎样从顶部开始逐层打印二叉树结点数据?请编程。 

 
7、怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)?

8、请编写能直接实现 int atoi(const char * pstr) 函数功能的代码。

9、编程实现两个正整数的除法
编程实现两个正整数的除法,当然不能用除法操作符。
// return x/y.
int div(const int x, const int y) 
{
....

10、在排序数组中,找出给定数字的出现次数

比如  [1, 2, 2, 2, 3]  中 2 的出现次数是 3 次。

11、平面上 N 个点,每两个点都确定一条直线,
求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。

12、一个整数数列,元素取值可能是 0~65535 中的任意一个数,相同数值不会重复出现。
0 是例外,可以反复出现。
请设计一个算法,当你从该数列中随意选取 5 个数值,判断这 5 个数值是否连续相邻。
注意:
- 5 个数值允许是乱序的。比如:  8 7 5 0 6
- 0 可以通配任意数值。比如:8 7 5 0 6  中的 0 可以通配成 9 或者 4
- 0 可以多次出现。
-  复杂度如果是 O(n2)则不得分。

13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。
复杂度如果是 O(n2)则不得分。

14、一棵排序二叉树,令  f=(最大值+最小值)/2,
设计一个算法,找出距离 f 值最近、大于 f 值的结点。
复杂度如果是 O(n2)则不得分。

15、一个整数数列,元素取值可能是 1~N (N 是一个较大的正整数)中的任意一个数,相
同数值不会重复出现。
设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于 N+1。
复杂度最好是 O(n),如果是 O(n2)则不得分。


二、解答



1、有一个整数数组,请求出两两之差绝对值最小的值,
记住,只要得出最小值即可,不需要求出是哪两个数。


解法: 


方法一:


先排序,然后比较相邻两数的差的绝对值,最后就可以得到最小的绝对值。如果用计数排序,复杂度是n。



方法二:


设这个整数数组是a1,a2,...,an


构造数组B=(b1,b2,...,bn-1)


b1 = a1-a2,


b2 = a2-a3,


b3 = a3-a4,


...


bn-1 = an-1 - an


那么原数组中,任意两整数之差ai-aj(1<=i,j<=n)可以表示成B中第i个到第j-1个元素的连续求和


例如b2+b3+b4 = (a2-a3) + (a3-a4) + (a4-a5) = a2-a5


O(n)构造出B序列后,用类似“最大子段和”算法求“最小绝对值子段和”




2、写一个函数,检查字符是否是整数,如果是,返回其整数值。
(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?) 

long strToInt(char *str,int length)//从最左边开始 
{
	if(length>1) 
		return str[0]=='-'? strToInt(str,length-1)*10-(str[length-1]-'0') : strToInt(str,length-1)*10+str[length-1]-'0';
	else 
		return str[0]=='-'? 0:str[0]-'0';
}

递归过程 


-23 ==> f(-2)*10-3 ==> ( f(-)*10-2 )*10-3  ==> (0*10-2)*10-3= -23



3、给出一个函数来输出一个字符串的所有排列。

同70题目:回溯法即可 


#include<iostream>
#include<stdio.h>
using namespace std;


void swap(char *a,char *b)
{
	char t;  
    t=*a;  
    *a=*b;  
    *b=t; 
}


void printAllArray(char a[],int n,int index)
{
	int i,j;
	if(index==n)
	{
		for(i=0;i<n;i++)
			printf("%c",a[i]);
		printf("\n");
		return ;
	}
	for(j=index;j<n;j++)
	{
		swap(&a[index],&a[j]);
		printAllArray(a,n,index+1);
		swap(&a[index],&a[j]);
	}
}
int main()
{
	char a[]="abcd";
	char b[]="swg";
	int len;
	//len=sizeof(a)/sizeof(char);//5
	len=strlen(a);
	printAllArray(a,len,0);//4*3*2=24种 
	
	printf("*****************\n");
	len=strlen(b);
	printAllArray(b,len,0);//3*2=6种 
	
	return 0;
}




4( a)请编写实现 malloc()内存分配函数功能一样的代码。
 (b) 给出一个函数来复制两个字符串A和 B。字符串A的后几个字节和字符串B的前几个字节重叠。


malloc()是C语言中动态存储管理的一组标准库函数之一。


其作用是在内存的动态存储区中分配一个长度为size的连续空间。


其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针


我觉得要用到系统调用了 操作系统了




(b)同85题目 



#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
#define N 101


void myStrcpy(char a[],char b[])
{
	char c[N];
	int len,len2,i,j,k,f;
	len=strlen(a);
	
	f=0;
	for(i=0;i<len;i++)//遍历a 开始查找当前i位置到结束是否是b的前缀 
	{
		k=i;j=0;
		while(a[k]==b[j])
		{
			k++;j++;
			if(k==len)
			{
				f=1;
				break;
			}	
		}
		if(f==1)
			break;
	}
	len2=strlen(b);
	for(k=0;k<i;k++)//从i开始 与b前面相同 
		c[k]=a[k];
	for(j=0;j<len2;k++,j++)
		c[k]=b[j]; 
	
	for(i=0;i<k;i++)
		printf("%c",c[i]);
	printf("\n");
}


int main()
{
	char a[]={"12345678"};
	char b[]={"56789322"};
	printf("串1:%s 串2:%s\n",a,b);
	printf("合并后的串为:"); 
	myStrcpy(a,b);
	
	char c[]={"fgaercxore"};
	char d[]={"ekkkkkkkfff"};
	printf("串1:%s 串2:%s\n",c,d);
	printf("合并后的串为:"); 
	myStrcpy(c,d);
	return 0;
}



5、怎样编写一个程序,把一个有序整数数组放到二叉树中? 


同86题 


有序的,直接中间分开 左右子树建立递归 


#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
#define N 101
struct  Node{
	int data;
	struct Node *left,*right;
}; 




Node* bulidTree(int array[], int start, int end) 
{
	if (start>end) 
		return NULL;
	int m=(start+end)/2;
	Node *root=(Node*)malloc(sizeof(Node));
	root->data=array[m];
	root->left=bulidTree(array,start,m-1);
	root->right=bulidTree(array,m+1,end);
	return root;
} 


// 中序遍历 左根右 
void displayTreeMid(Node *head) 
{
	if(head->left)
		displayTreeMid(head->left);
	printf("%d ",head->data);
	if(head->right)
		displayTreeMid(head->right);
}
// 前序遍历 根左右 
void displayTreeFore(Node *head) 
{
	printf("%d ",head->data);
	if(head->left)
		displayTreeFore(head->left);
	if(head->right)
		displayTreeFore(head->right);
}


// 后序遍历 左右根 
void displayTreeBack(Node *head) 
{
	if(head->left)
		displayTreeBack(head->left);
	if(head->right)
		displayTreeBack(head->right);
	printf("%d ",head->data);
}


int main()
{
	/*
			  5
		  2	     7
		1  3   6  8
		    4      9
	中序遍历:1 2 3 4 5 6 7 8 9
	前序遍历:5 2 1 3 4 7 6 8 9
	后序遍历:1 4 3 2 6 9 8 7 5
	*//* 
	int array[]={1,2,3,4,5,6,7,8,9};
	Node *root;
	root=bulidTree(array,0,sizeof(array)/sizeof(int)-1);
	printf("中序遍历:");
	displayTreeMid(root);
	printf("\n");
	 
	printf("前序遍历:");
	displayTreeFore(root);
	printf("\n");
	
	printf("后序遍历:");
	displayTreeBack(root);
	printf("\n");
	return 0;
}


 


6、怎样从顶部开始逐层打印二叉树结点数据?请编程。

同16题



/*
第 16  题:
题目(微软): 
输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往右的顺序打印。
		8
      /  \
	 6   10
	/ \  / \
   5  7 9  11
打印出来:8 6 10 5 7 9 11


BFS广度优先搜索 




#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<queue> 
using namespace std;
#define MAX 20


struct BTreeNode{
	int data;
	BTreeNode *left,*right;
}; 


//建立二叉树 
BTreeNode * CreateTree(int data[],int pos,int len)
{
	BTreeNode *tree;
	if(pos>=len) 
	{
		return NULL;
	}
	else
	{
		tree=(BTreeNode *)malloc(sizeof(BTreeNode));
		tree->data=data[pos];
		tree->left=CreateTree(data,2*pos+1,len);//数组坐标 
		tree->right=CreateTree(data,2*pos+2,len);
		return tree;
	}
	
}


void InOrder(BTreeNode *tree)
{
	if(tree!=NULL)
	{
		InOrder(tree->left);
		printf("%d ",tree->data);
		InOrder(tree->right);
	}
}


void BFS(BTreeNode *root)
{
	BTreeNode *temp,*start;
	queue<BTreeNode *> q;
	
	q.push(root);
	while(!q.empty())
	{
		start=q.front();
		q.pop();
		
		if(start->left!=NULL)
			q.push(start->left);
		
		if(start->right!=NULL)
			q.push(start->right);
		printf("%d ",start->data);	
	}
}


int main(){
	
	int data[]={8,6,10,5,7,9,11};
	int len=sizeof(data)/sizeof(int);
	
	BTreeNode *tree=CreateTree(data,0,len);


	printf("中序遍历:\n");//左根右 
	InOrder(tree);printf("\n");
	printf("打印结果:\n");
	BFS(tree);printf("\n");
	
	return 0;
}



7、怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)?


同 第 24  题:



node * reverseNonrecurse(node *head)
{
	if(head==NULL) return head;
	
	node *p=head,*previous=NULL,*next=NULL;
	
	while(p->next!=NULL)
	{
		next=p->next;//保存下一个 
		p->next=previous;//p下一个为他前面的
		previous=p;
		p=next; 
	}
	p->next=previous;
	return p;
}




8、请编写能直接实现 int atoi(const char * pstr) 函数功能的代码。


同89题:


#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;


int atoi(char* a) 
{
	if (*a=='+')
		return atoi(a+1);
	else if(*a=='-') 
		return -atoi(a+1);
		
	char *p=a;
	int ans=0;
	while(*p>='0'&&*p<='9') 
	{
		ans=ans*10+(*p-'0');
		p++;
	}
	return ans;
}
int main()
{
	
	char a[]={"+123"};
	printf("%s:符串转整型为:%d\n",a,atoi(a)); 
	
	char b[]={"-123"};
	printf("%s:符串转整型为:%d\n",b,atoi(b)); 
	
	char c[]={"123CS45"};
	printf("%s:符串转整型为:%d\n",c,atoi(c)); 
	
	char d[]={"123.45CS"};
	printf("%s:符串转整型为:%d\n",d,atoi(d)); 
	
	char e[]={"CS123.45"};
	printf("%s:符串转整型为:%d\n",e,atoi(e));
	return 0;
}



9、编程实现两个正整数的除法
编程实现两个正整数的除法,当然不能用除法操作符。

// return x/y.


int div(const int x, const int y) 


{


....




解法 循环模拟


void devide(int val1, int val2, int& res, int &rev) //两个值val1 val2 商res 余数rev 
{  
    int maxv = max(val1, val2);  
    int minv = min(val1, val2);  
    res=0;  rev = 0;  
    if(maxv == minv){  
        res = 1;  
        rev = 0;  
        return;  
    }
	else
	{  
        while(maxv>minv)
		{  
            maxv=maxv-minv;  
            res+=1;  
        }  
        rev=maxv;  
        return;  
    }  
}



10、在排序数组中,找出给定数字的出现次数
比如  [1, 2, 2, 2, 3]中2的出现次数是3次。


我不管有没排好序 二分查找 


void countNum(int a[],int start,int finish,int num)
{
 
    int middle=(start+finish)/2;
    if(start>finish)
      return ;


    if(a[middle]==num)
    {
        count++;
        countNum(a,start,middle-1,num);
        countNum(a,middle+1,finish,num);
    }
	else if(a[middle]>num)
        countNum(a,start,middle-1);
	else
       countNum(a,middle+1,finish);
}


 


11、平面上N个点,每两个点都确定一条直线,
求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。


3个点A,B,C,把它们的按x坐标排序。假设排序后的顺序是ABC,那么有两种情况:


1.ABC共线,则k(AB)=k(BC)=k(AC)


2.ABC不共线,则ABC将形成一个三角形,那么k(AC)<max(k(AB), k(BC))


其中k()表示求斜率。



所以程序的基本步骤就是:


1.把N个点按x坐标排序。


2.遍历,求相邻的两个点的斜率,找最大值。


时间复杂度Nlog(N)。


先把这些点按x坐标从小到大排序,斜率最大的两点必然是挨一起的两个点,




12、一个整数数列,元素取值可能是 0~65535 中的任意一个数,相同数值不会重复出现。
0例外,可以反复出现。请设计一个算法,当你从该数列中随意选取5个数值,

判断这5个数值是否连续相邻。


注意:


- 5个数值允许是乱序的。比如:8 7 5 0 6


- 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者 4


- 0可以多次出现。


- 复杂度如果是 O(n2)则不得分。




//排序,遍历得到非0的最小值和最大值,两者只差小于5即连续相邻



给出一个类似的题目 67题 


/*
67.俩个闲玩娱乐。
1.扑克牌的顺子
从扑克牌中随机抽 5  张牌,判断是不是一个顺子,即这 5  张牌是不是连续的。2-10  为数
字本身,A为1,J 11,Q为12,K为13,而大小王可以看成任意数字。


5张牌看成由5个数字组成的数组。大小王当成0.我们把数组排序。由于0可以当成任意数字,
我们可以用0去补满数组中的空缺。也就是排序之后的数组不是连续的,
即相邻的两个数字相隔若干个数字,但如果我们有足够的0可以补满这两个数字的空缺,
这个数组实际上还是连续的。
{0,1,3,4,5}。0可以当成2去填补这个空缺,所以是顺子 
*/
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;


bool checkGaps(int a[],int s,int e,int allowGaps)
{
	int i=s;
	while(i<e)
	{
		allowGaps-=a[i+1]-(a[i]+1);
		if(allowGaps<0)
			return false;
		i++;
	}
	return true;
}


bool isStraight(int a[])
{
	sort(a,a+5);
	if(a[0]>0)
		return checkGaps(a,0,4,0);
	else if(a[0]==0&&a[1]!=0)
		return checkGaps(a,1,4,1);
	return checkGaps(a,2,4,2);
}


int main()
{
	int i;
	int a[]={1,0,3,4,5};
	int b[]={0,0,9,5,6};
	int c[]={1,0,2,3,6};
	
	for(i=0;i<5;i++)
		printf("%d",a[i]);
	if(isStraight(a))
		printf(" is straight.\n");
	else
		printf(" is not straight.\n");
		
		
	for(i=0;i<5;i++)
		printf("%d",b[i]);
	if(isStraight(b))
		printf(" is straight.\n");
	else
		printf(" is not straight.\n");
		
		
	for(i=0;i<5;i++)
		printf("%d",c[i]);
	if(isStraight(c))
		printf(" is straight.\n");
	else
		printf(" is not straight.\n");
	
	return 0;
}



13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。
复杂度如果是 O(n2)则不得分。

同75题:



/*
75.二叉树两个结点的最低共同父结点
题目:二叉树的结点定义如下:
struct TreeNode
{
int  m_nvalue;
TreeNode*  m_pLeft;
TreeNode*  m_pRight;
}; 
输入二叉树中的两个结点,输出这两个结点在数中最低的共同父结点。


对于一个子树的根结点来说,如果那两个结点分别位于该子树的左右子树,则最低共同父结点为该子树的根结点,
如果那两个结点都位于该子树的左子树,则最低共同父结点位于该子树根结点的左子树,
否则来自右子树。递归
*/


//寻找二叉树两个结点的最低共同父节点
TreeNode *FindFirstCommonParentNode(TreeNode *pRoot, TreeNode *pNodeOne, TreeNode *pNodeTwo)
{
    if (NULL==pRoot)
    {
        return NULL;
    }
    if (pRoot==pNodeOne || pRoot==pNodeTwo)
    {
        return pRoot;
    }
    TreeNode *pLeft = FindFirstCommonParentNode(pRoot->m_pLeft, pNodeOne, pNodeTwo);
    TreeNode *pRight = FindFirstCommonParentNode(pRoot->m_pRight, pNodeOne, pNodeTwo);


    if (NULL==pLeft) //1、左子树没有找到任何一个结点,则第一个公共父节点必定在右子树,而且找到第一个结点就是最低共同父节点
    {
        return pRight;
    }
    else if (NULL==pRight) //2、右子树没有找到任何一个结点,则第一个公共父节点必定在左子树,而且找到第一个结点就是最低共同父节点
    {
        return pLeft;
    }
    else          //3、分别在结点的左右子树找到,则此节点必为第一个公共父节点
    {
        return pRoot;
    }
}


14、一棵排序二叉树,令 f=(最大值+最小值)/2,
设计一个算法,找出距离f值最近、大于f值的结点。
复杂度如果是 O(n2)则不得分。


算法思想:最小最大节点分别在最左下与最右下节点,O(N)


static BinNode Find(BinNode root)
{
    BinNode min = FindMinNode(root);
    BinNode max = FindMaxNode(root);
    double find = (double)(min.Element+max.Element) / 2;
    return FindNode(root, find);
}
 
static BinNode FindMinNode(BinNode root)
{
    BinNode min = root;
    while (min.Left != null)
    {
        min = min.Left;
    }
    return min;
}


static BinNode FindMaxNode(BinNode root)
{
    BinNode max = root;
    while (max.Right != null)
    {
        max = max.Right;
    }
    return max;
}


递归寻找BST的节点,O(logN)。
static BinNode FindNode(BinNode root, double mid)
{           
    //如果小于相等,则从右边找一个最小值
    if (root.Element<= mid)
    {
        if (root.Right == null)
            return root;
        BinNode find=FindNode(root.Right, mid);
        //不一定找得到
        return find.Element < mid ? root : find;
    }
    //如果大于,则找到Left
    else  //temp.Element > find
    {
        if (root.Left == null)
            return root;
        BinNode find = FindNode(root.Left, mid);
        //不一定找得到
        return find.Element < mid ? root : find;
    }
}



15、一个整数数列,元素取值可能是 1~N (N 是一个较大的正整数)中的任意一个数,相
同数值不会重复出现。
设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。
复杂度最好是 O(n),如果是 O(n2)则不得分。


1、前后双指针(但是有排序过程要做,这个费时看情况)最快也是O(nlgn)


void find2Number(int a[],int n,int dest)
{
	int *f=a,*e=a+n-1;
	int sum=*f+*e;
	while(sum!=dest&&f<e)
	{
		if(sum<dest) 
			sum=sum-*f+*(++f);
		else
			sum=sum-*e+*(--e);
	}
	if(sum==dest)
		printf("%d+%d=%d\n",*f,*e,dest);
}


2.用空换时间的做法:


int main()  
{  
    int a[] = {1,3,4,7,8,9,10};  
    int sum = 11;  
    int len = sizeof(a)/sizeof(int);  
    int *b = (int *)malloc(sizeof(len));  
    
    for(int i=0;i<len;i++)  
        b[i]=sum-a[i];  
    int high = len-1;  
    int low = 0;  
    while(low<high)  
    {  
        if(a[low]==b[high])  
        {  
            cout<<a[high]<<" + "<<b[high]<<" = "<<sum<<endl;  
            low++;  
            high--;  
        }else if(a[low] > b[high])  
        {  
            high--;  
        }else{  
            low++;  
        }  
    }  
    getchar();  
    return 0;  
}

举报

相关推荐

0 条评论