您的位置:首页 > 理论基础 > 数据结构算法

微软等数据结构+算法面试100题(48)-- 微软十五道面试题

2012-11-12 10:29 567 查看
微软十五道面试题

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、有一个整数数组,请求出两两之差绝对值最小的值,
记住,只要得出最小值即可,不需要求出是哪两个数。

思路:先排序。排序后两两之差绝对值最小的值肯定是相邻元素的差的绝对值。这样时间复杂度是nlogn。
*/


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


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

思路:首相对数列排序,排序复杂度为nlogn。排序后设俩个下标分别指向最小和最大的low,high。
如果p[low]+p[high]==n+1,找到。
如果p[low]+p[high]>n+1,high--。
如果p[low]+p[high]<n+1,low++。
当low>high的时候即可退出。
*/


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

思路:对于一个二叉排序树而言。最大最小值分别是最左和最右子节点的值。
这样可以计算出f的值。复杂度是logn。然后就是从根节点开始遍历一遍二叉排序树。
如果root->data==f;root=root->right;
如果root->data>f;root=root->left;node=root;
如果root->data<f;root=root->right;
最后返回node值即可。
*/


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

思路:首先找到从根节点到俩个节点的俩条路径。找到路径后就是比较俩条路劲。找到最后一个相等的节点。
*/


/*
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最大最小分别是max和min。max-min+1应该要<=5。这样才能连续相邻。
*/


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

思路:首先按照横坐标排序。因为俩个横坐标离得越近斜率越大。排序后就计算相邻俩点的斜率。求最大的。
*/


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

思路:如果一个一个比较。复杂度是n。
考虑到已经排好序了。所以可以采用二分搜索的思路。求出给定数字的lowbound和upperbound。这样
upperbound-lowbound就是给定数字出现的次数。而计算lowbound和upperbound复杂度都是logn。
所以最后时间复杂度也是logn。这样比逐个比较复杂度低。
*/
int LowBound(int *p,int low,int high,int n)
{
while(low<high)
{
int mid=low+(high-low)/2;
if(p[mid]>=n)
high=mid;
else
low=mid+1;
}
return low;
}

int UpperBound(int *p,int low,int high,int n)
{
while(low<high)
{
int mid=low+(high-low)/2;
if(p[mid]>n)
high=mid;
else
low=mid+1;
}
return low;
}


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

这个题说白了就是在1到x之间找到一个数res。使得res*y<x但是(res+1)*y>x。
思路1:就是从1开始一直到x这样的比较。
思路2:既然是从1到x,其实也是可以用二分的思路。
*/

int Div(const int x, const int y)
{
int res=-1;
for(int i=1;i<=x;i++)
{
if(i*y<x)
res=i;
}
return res;
}

int Div1(const int x, const int y)
{
int low=1,high=x;
while(low<high)
{
int mid=low+((high-low)>>1);
int tmp=x-mid*y;
if(tmp>=y)
low=mid;
if(tmp<0)
high=mid;
}
}


// MS.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

using namespace std;

typedef vector<int>::iterator Iter;

//单链表节点
struct ListNode
{
int data;
ListNode* next;
ListNode(int value=0,ListNode *pnext=NULL):data(value),next(pnext){}
};

//二叉树节点
struct TreeNode
{
int data;
TreeNode *left;
TreeNode *right;
TreeNode(int value=0,TreeNode *pleft=NULL,TreeNode *pright=NULL):data(value),left(pleft),right(pright){}
};

void ShowArray(int *p,int len)
{
for(int i=0;i<len;i++)
cout<<p[i]<<" ";
cout<<endl;
}

void MidOrderTraverse(TreeNode* root)
{
if(root==NULL)
return;
MidOrderTraverse(root->left);
cout<<root->data<<" ";
MidOrderTraverse(root->right);
}

/*
微软十五道面试题

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)则不得分。
*/

/* 15、一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。 设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。 复杂度最好是O(n),如果是O(n2)则不得分。 思路:首相对数列排序,排序复杂度为nlogn。排序后设俩个下标分别指向最小和最大的low,high。 如果p[low]+p[high]==n+1,找到。 如果p[low]+p[high]>n+1,high--。 如果p[low]+p[high]<n+1,low++。 当low>high的时候即可退出。 */

/* 14、一棵排序二叉树,令 f=(最大值+最小值)/2, 设计一个算法,找出距离f值最近、大于f值的结点。 复杂度如果是O(n2)则不得分。' 思路:对于一个二叉排序树而言。最大最小值分别是最左和最右子节点的值。 这样可以计算出f的值。复杂度是logn。然后就是从根节点开始遍历一遍二叉排序树。 如果root->data==f;root=root->right; 如果root->data>f;root=root->left;node=root; 如果root->data<f;root=root->right; 最后返回node值即可。 */

/* 13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。 复杂度如果是O(n2)则不得分。 思路:首先找到从根节点到俩个节点的俩条路径。找到路径后就是比较俩条路劲。找到最后一个相等的节点。 */

/* 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最大最小分别是max和min。max-min+1应该要<=5。这样才能连续相邻。 */

/* 11、平面上N个点,每两个点都确定一条直线, 求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。 思路:首先按照横坐标排序。因为俩个横坐标离得越近斜率越大。排序后就计算相邻俩点的斜率。求最大的。 */

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

思路:如果一个一个比较。复杂度是n。
考虑到已经排好序了。所以可以采用二分搜索的思路。求出给定数字的lowbound和upperbound。这样
upperbound-lowbound就是给定数字出现的次数。而计算lowbound和upperbound复杂度都是logn。
所以最后时间复杂度也是logn。这样比逐个比较复杂度低。
*/

/* 1、有一个整数数组,请求出两两之差绝对值最小的值, 记住,只要得出最小值即可,不需要求出是哪两个数。 思路:先排序。排序后两两之差绝对值最小的值肯定是相邻元素的差的绝对值。这样时间复杂度是nlogn。 */

int GetAbsMin(int *p,int len)
{
std::sort(p,p+len);
cout<<"after sort : ";
ShowArray(p,len);
int min=numeric_limits<int>::max();
for(int i=1;i<len;i++)
{
int tmp=abs(p[i]-p[i-1]);
if(tmp<min)
min=tmp;
}
return min;
}

void GetAbsMinTest()
{
int p[]={23,10,-10,8,-19,2,7,0,44,58,4};
int len=sizeof(p)/sizeof(int);
cout<<"the array : ";
ShowArray(p,len);
int min=GetAbsMin(p,len);
cout<<"the minmal abs diff : "<<min<<endl;
}

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

//这里在处理的时候没有考虑到正负数的问题,以及空格非法字符等。
int MyAtio(char* str)
{
int res=0;
for(int i=0;str[i]!='\0';i++)
res=res*10+str[i]-'0';
return res;
}

int Atio(char* str)
{
int sign=1;//先认为它是一个正数。
int i=0;
while(str[i]!='\0'&&str[i]==' ')
i++;
if(str[i]=='-')
{sign=-1;i++;}
if(str[i]=='+')
i++;
int res=0;
for(;str[i]!='\0';i++)
res=res*10+str[i]-'0';
return sign==1?res:res*(-1);
}

void AtioTest()
{
char str[]=" +12340";
cout<<"str : "<<str<<endl;
int num=Atio(str);
cout<<"str to num : "<<num<<endl;
}

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

思路:例如要输出abcd的全排列。
对于第一个位置,可以取a、b、c、d四个。我们选取完以后,第一个位置处的字符就确定下来了。
然后就是从第二个位置开始全排列。这里就是一个递归的过程
例如一个字符str。下标从[low....high]。首先要选定low位置的字符。假定选择了i处的字符(low<=i<=high)。
继续对[low+1....high]这些字符全排。排完之后要将i和low位置处的元素交换回来
*/
void StrArrange(char* str,int low,int high)
{
if(low==high)
cout<<str<<endl;
else
{
for(int i=low;i<=high;i++)
{
swap(str[low],str[i]);
StrArrange(str,low+1,high);
swap(str[low],str[i]);
}
}
}

void StrArrange(char* str)
{
if(str==NULL)
return;
int high=strlen(str)-1;
StrArrange(str,0,high);
}

void StrArrangeTest()
{
char str[]="abcd";
cout<<"str : "<<str<<endl;
cout<<"str arrange : "<<endl;
StrArrange(str);
}

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

思路:
(a)实现内存分配比较难
(b)主要是找到从哪个字符开始A的后几个字节开始和B的开始几个字节重叠。这里类似于字符串匹配。
*/

//计算从哪个位置开始俩个开始重叠。其实就是字符串匹配的代码稍作修改即可
int GetStrStartIndex(char* str,char* substr)
{
int len=strlen(str);
int len1=strlen(substr);
int i=0,j=0;
while(i<len)
{
if(str[i]==substr[j])
{
i++;
j++;
if(i==len)
return i-j;
}
else
{
i=i-j+1;
j=0;
}
}
return len;
}

void CopyAB(char* str,char* substr,char* output)
{
int index=GetStrStartIndex(str,substr);
int len1=strlen(substr);
int i=0,j=0,k=0;
//拷贝的时候先拷贝A中的字符,一直到index。
while(i<index)
{
output[k]=str[i];
k++;i++;
}
//到了index就可以开始拷贝B中的字符了
while(j<=len1)
{
output[k]=substr[j];
k++;j++;
}
}

void GetStrStartIndexTest()
{
char str[]="hello world!";
char substr[]="ldlhh";
char output[50];
cout<<"str : "<<str<<endl;
cout<<"substr : "<<substr<<endl;
int index=GetStrStartIndex(str,substr);
cout<<"start index : "<<index<<endl;
CopyAB(str,substr,output);
cout<<"merge str and substr : "<<output<<endl;
}

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

思路:这是一个递归的过程。例如数组p[low...mid.....high]。
那么我们让p[mid]作为根节点。p[low...mid-1]作为左子树。p[mid+1....high]作为右子树。
如果low>high。那么节点为空
如果low==high。那么将p[low]作为节点值
如果low<high。分为俩部分去递归
*/

void PutArrayInTree(int *p,int low,int high,TreeNode* &root)
{
if(low>high)
root=NULL;
else if(low==high)
root=new TreeNode(p[low]);
else
{
int mid=low+(high-low)/2;
root=new TreeNode(p[mid]);
PutArrayInTree(p,low,mid-1,root->left);
PutArrayInTree(p,mid+1,high,root->right);
}
}

void PutArrayInTreeTest()
{
int p[]={20,10,-1,5,19,7,-2,0,3,17,2,22,-15};
int len=sizeof(p)/sizeof(int);
cout<<"the array : ";
ShowArray(p,len);
std::sort(p,p+len);
cout<<"after sort : ";
ShowArray(p,len);
TreeNode* root=NULL;
PutArrayInTree(p,0,len-1,root);
cout<<"MidOrderTraverse : ";
MidOrderTraverse(root);
cout<<endl;
}

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

思路:二叉树的层序遍历属于广度遍历。所以我们借助队列来完成。
开始队列中只有一个根节点。我们访问这个节点,然后判断这个节点是不是存在左右子节点。
存在的话就进队。只要队列不为空。每次从队列头部弹出一个元素。访问这个元素。并且将这个元素的左右子节点
进队。
*/

void LayerTraverse(TreeNode* root)
{
if(root==NULL)
return;
queue<TreeNode*> qu;
TreeNode *last=root;
qu.push(root);
while(!qu.empty())
{
TreeNode *root=qu.front();
cout<<root->data<<" ";
if(root->left!=NULL)
qu.push(root->left);
if(root->right!=NULL)
qu.push(root->right);
if(last==root)
{
if(!qu.empty())
last=qu.back();
cout<<endl;
}
qu.pop();
}
}

void LayerTraverseTest()
{
int p[]={20,10,-1,5,19,7,-2,0,3,17,2,22,-15};
int len=sizeof(p)/sizeof(int);
cout<<"the array : ";
ShowArray(p,len);
std::sort(p,p+len);
cout<<"after sort : ";
ShowArray(p,len);
TreeNode* root=NULL;
PutArrayInTree(p,0,len-1,root);
cout<<"MidOrderTraverse : ";
MidOrderTraverse(root);
cout<<endl;
cout<<"LayerTraverse : ";
LayerTraverse(root);
cout<<endl;
}

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

思路:假如有一个头结点为head的单链表。
如果head==NULL。直接返回
如果head->next==NULL。说明链表中只有一个元素。直接返回。
否则至少有俩个元素。
*/

void ReverseList(ListNode* &head)
{
if(head==NULL)
return;
if(head->next==NULL)
return;
ListNode* pre=NULL;
ListNode* p=head;
while(p!=NULL)
{
ListNode* q=p->next;
p->next=pre;
pre=p;
p=q;
}
head=pre;
}

//建立一个链表
void MakeList(ListNode* &head)
{
int value=0;
while(cin>>value)
{
if(head==NULL)
head=new ListNode(value);
else
{
ListNode *node=new ListNode(value);
node->next=head;
head=node;
}
}
}
//打印一个链表
void ShowList(ListNode *head)
{
while(head!=NULL)
{
cout<<head->data<<" ";
head=head->next;
}
cout<<endl;
}

void ShowListReverseTest()
{
cout<<"make a list , input values "<<endl;
ListNode* head=NULL;
MakeList(head);
cout<<"the list : ";
ShowList(head);
cout<<"show list from end to head : ";
ReverseList(head);
ShowList(head);
cout<<endl;
}

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

int Div(const int x, const int y,int low,int high)
{
if(low==high)
return low;
if(low+1==high)
{
if(high*y<=x)
return high;
if(y*low<=x&&high*y>x)
return low;
}
int mid=low+((high-low)>>1);
if(mid*y>x)
return Div( x, y,low,mid-1);
else
return Div( x, y,mid,high);
}

int Div(const int x, const int y)
{
int low=1,high=x;
return Div(x, y,low,high);
}

void DivTest()
{
cout<<"input x : ";
int x=0;
cin>>x;
cout<<"input y : ";
int y=0;
cin>>y;
cout<<"x/y : "<<Div(x,y)<<endl;
}

/*
10、在排序数组中,找出给定数字的出现次数
比如 [1, 2, 2, 2, 3] 中2的出现次数是3次。
*/
int UpperBound(int *p,int low,int high,int n)
{
if(low==high)
return low;
if(low+1==high)
{
if(p[high]==n)
return high+1;
if(p[low]==n)
return high;
}
int mid=low+(high-low)/2;
if(p[mid]>n)
return UpperBound(p,low,mid,n);
else
return UpperBound(p,mid,high,n);
}

int LowerBound(int *p,int low,int high,int n)
{
if(low==high)
return low;
int mid=low+(high-low)/2;
if(p[mid]>=n)
return LowerBound(p,low,mid,n);
else
return LowerBound(p,mid+1,high,n);
}

void BoundTest()
{
int p[]={20,10,-1,5,19,7,-2,0,3,17,2,22,-15,2,19,10,2,22,19};
int len=sizeof(p)/sizeof(int);
cout<<"the array : ";
ShowArray(p,len);
std::sort(p,p+len);
cout<<"after sort : ";
ShowArray(p,len);

int low=0,high=len-1;
int n=0;
cout<<"input a num : ";
cin>>n;
int lowindex=LowerBound(p,low,high,n);
int highindex=UpperBound(p,low,high,n);
cout<<"lowerbound : "<<lowindex<<endl;
cout<<"upperbound : "<<highindex<<endl;
}

int _tmain(int argc, _TCHAR* argv[])
{
BoundTest();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐