几道面试题的求解
2007-10-24 10:24
375 查看
给定九个数,例如:1,3,3,5,6,7,8,8,9计算出这九个数的排列的种数。需要考虑重复情况,如果给定9个1,则只有一种结果。
限制:不能使用stl库
要求:完成函数 unsigned int foo(unsigned int *arr);
输入算法代码,并给出算法复杂度分析。
分析:
#include <cstdlib>
#include <iostream>
using namespace std;
unsigned int foo(unsigned int *arr)
{
unsigned int p[] ={1,2,6,24,120,720,5040,40320,362880};
unsigned int i,j,c,s=p[8];//first the number is p99
for(i = 0; i < 7; i++)
for(j = i+1; j < 8; j++)
{
if(arr[i]>arr[j]) //swap two number
{
arr[i]^=arr[j];
arr[j]^=arr[i];
arr[i]^=arr[j];
}
}
i = 0;
c = 0;
while(i<8)
{
j = i+1;
while(arr[i]==arr[j])//compute the number of the repetition
{
c++;
j++;
}
s/=p[c];
c=0;
i=j;
}
return s;
}
int main()
{
unsigned int a[]={1,3,3,5,6,7,8,8,9};
cout<<"The number of permutation is: "<<foo(a)<<endl;
system("pause");
return 0;
}
题目:输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
分析:这是一道很有意思的面试题。该题以及它的变体经常出现在各大公司的面试、笔试题中。
看到这道题后,第一反应是从头到尾输出比较简单。于是很自然地想到把链表中链接结点的指针反转过来,改变链表的方向。然后就可以从头到尾输出了。反转链表的算法详见本人面试题精选系列的第19题,在此不再细述。但该方法需要额外的操作,应该还有更好的方法。
接下来的想法是从头到尾遍历链表,每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始输出结点的值,此时输出的结点的顺序已经反转过来了。该方法需要维护一个额外的栈,实现起来比较麻烦。
既然想到了栈来实现这个函数,而递归本质上就是一个栈结构。于是很自然的又想到了用递归来实现。要实现反过来输出链表,我们每访问到一个结点的时候,先递归输出它后面的结点,再输出该结点自身,这样链表的输出结果就反过来了。
基于这样的思路,不难写出如下代码:
///////////////////////////////////////////////////////////////////////
// Print a list from end to beginning
// Input: pListHead - the head of list
///////////////////////////////////////////////////////////////////////
void PrintListReversely(ListNode* pListHead)
{
if(pListHead != NULL)
{
// Print the next node first
if (pListHead->m_pNext != NULL)
{
PrintListReversely(pListHead->m_pNext);
}
// Print this node
printf("%d", pListHead->m_nKey);
}
}
扩展:该题还有两个常见的变体:
1. 从尾到头输出一个字符串;
2. 定义一个函数求字符串的长度,要求该函数体内不能声明任何变量。
给一个天平,问如何用3次把这个小球找出来
并且求出这个小球是比其他的轻还是重
将12个球分别编号为a1,a2,a3.......a10,a11,a12.
第一步:将12球分开3拨,每拨4个,a1~a4第一拨,记为b1, a5~a6第2拨,记为b2,其余第3拨,记为b3;
第二步:将b1和b2放到天平两盘上,记左盘为c1,右为c2;这时候分两中情况:
1.c1和c2平衡,此时可以确定从a1到a8都是常球;然后把c2拿空,并从c1上拿下a4,从a9到a12四球里随便取三球,假设为a9到a11,放到c2上。此时c1上是a1到a3,c2上是a9到a11。从这里又分三种情况:
A:天平平衡,很简单,说明没有放上去的a12就是异球,而到此步一共称了两次,所以将a12随便跟11个常球再称一次,也就是第三次,马上就可以确定a12是重还是轻;
B:若c1上升,则这次称说明异球为a9到a11三球中的一个,而且是比常球重。取下c1所有的球,并将a8放到c1上,将a9取下,比较a8和a11(第三次称),如果平衡则说明从c2上取下的a9是偏重异球,如果不平衡,则偏向哪盘则哪盘里放的就是偏重异球;
C:若c1下降,说明a9到a11里有一个是偏轻异球。次种情况和B类似,所以接下来的步骤照搬B就是;
2.c1和c2不平衡,这时候又分两种情况,c1上升和c1下降,但是不管哪种情况都能说明a9到a12是常球。这步是解题的关键。也是这个题最妙的地方。
A:c1上升,此时不能判断异球在哪盘也不能判断是轻还是重。取下c1中的a2到a4三球放一边,将c2中的a5和a6放到c1上,然后将常球a9放到c2上。至此,c1上是a1,a5和a6,c2上是a7,a8和a9。此时又分三中情况:
1)如果平衡,说明天平上所有的球都是常球,异球在从c1上取下a2到a4中。而且可以断定异球轻重。因为a5到a8都是常球,而第2次称的时候c1是上升的,所以a2到a4里必然有一个轻球。那么第三次称就用来从a2到a4中找到轻球。这很简单,随便拿两球放到c1和c2,平衡则剩余的为要找球,不平衡则哪边低则哪个为要找球;
2)c1仍然保持上升,则说明要么a1是要找的轻球,要么a7和a8两球中有一个是重球(这步懂吧?好好想想,很简单的。因为a9是常球,而取下的a2到a4肯定也是常球,还可以推出换盘放置的a5和a6也是常球。所以要么a1轻,要么a7或a8重)。至此,还剩一次称的机会。只需把a7和a8放上两盘,平衡则说明a1是要找的偏轻异球,如果不平衡,则哪边高说明哪个是偏重异球;
3)如果换球称第2次后天平平衡打破,并且c1降低了,这说明异球肯定在换过来的a5和a6两求中,并且异球偏重,否则天平要么平衡要么保持c1上升。确定要找球是偏重之后,将a5和a6放到两盘上称第3次根据哪边高可以判定a5和a6哪个是重球;
B:第1次称后c1是下降的,此时可以将c1看成c2,其实以后的步骤都同A,所以就不必要再重复叙述了。至此,不管情况如何,用且只用三次就能称出12个外观手感一模一样的小球中有质量不同于其他11球的偏常的球。而且在称的过程中可以判定其是偏轻还是偏重。
3.U2 合唱团在17 分钟内得赶到演唱会场,途中必需跨过一座桥,四个人从桥的同一端出发,
你得帮助他们到达另一端,天色很暗,而他们只有一只手电筒。一次同时最多可以有两人 一
起过桥,而过桥的时候必须持有手电筒,所以就得有人把手电筒带来带去,来回桥两端 。
手电筒是不能用丢的方式来传递的。四个人的步行速度各不同,若两人同行则以较慢者 的
速度为准。Bono 需花1 分钟过桥,Edge 需花2 分钟过桥,Adam需花 5 分钟过桥,Larry 需
花 10 分钟过桥。他们要如何在 17 分钟内过桥呢?(有个同济的学生写文章说他当时在微
软面 试时就是碰到了这道题,最短只能做出在 19分钟内过桥,微软的人对他讲这样的结果
已经 是不错的了!)
A点到 B 点
1 和2 过去 2 分钟 2
2 过来 4 分钟 2+2=4
10和 5过去 14 分钟 4+10=14
1 过来 15 分钟 14+1=15
1 和2 过去 17 分钟 15+2=17
限制:不能使用stl库
要求:完成函数 unsigned int foo(unsigned int *arr);
输入算法代码,并给出算法复杂度分析。
分析:
#include <cstdlib>
#include <iostream>
using namespace std;
unsigned int foo(unsigned int *arr)
{
unsigned int p[] ={1,2,6,24,120,720,5040,40320,362880};
unsigned int i,j,c,s=p[8];//first the number is p99
for(i = 0; i < 7; i++)
for(j = i+1; j < 8; j++)
{
if(arr[i]>arr[j]) //swap two number
{
arr[i]^=arr[j];
arr[j]^=arr[i];
arr[i]^=arr[j];
}
}
i = 0;
c = 0;
while(i<8)
{
j = i+1;
while(arr[i]==arr[j])//compute the number of the repetition
{
c++;
j++;
}
s/=p[c];
c=0;
i=j;
}
return s;
}
int main()
{
unsigned int a[]={1,3,3,5,6,7,8,8,9};
cout<<"The number of permutation is: "<<foo(a)<<endl;
system("pause");
return 0;
}
题目:输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
分析:这是一道很有意思的面试题。该题以及它的变体经常出现在各大公司的面试、笔试题中。
看到这道题后,第一反应是从头到尾输出比较简单。于是很自然地想到把链表中链接结点的指针反转过来,改变链表的方向。然后就可以从头到尾输出了。反转链表的算法详见本人面试题精选系列的第19题,在此不再细述。但该方法需要额外的操作,应该还有更好的方法。
接下来的想法是从头到尾遍历链表,每经过一个结点的时候,把该结点放到一个栈中。当遍历完整个链表后,再从栈顶开始输出结点的值,此时输出的结点的顺序已经反转过来了。该方法需要维护一个额外的栈,实现起来比较麻烦。
既然想到了栈来实现这个函数,而递归本质上就是一个栈结构。于是很自然的又想到了用递归来实现。要实现反过来输出链表,我们每访问到一个结点的时候,先递归输出它后面的结点,再输出该结点自身,这样链表的输出结果就反过来了。
基于这样的思路,不难写出如下代码:
///////////////////////////////////////////////////////////////////////
// Print a list from end to beginning
// Input: pListHead - the head of list
///////////////////////////////////////////////////////////////////////
void PrintListReversely(ListNode* pListHead)
{
if(pListHead != NULL)
{
// Print the next node first
if (pListHead->m_pNext != NULL)
{
PrintListReversely(pListHead->m_pNext);
}
// Print this node
printf("%d", pListHead->m_nKey);
}
}
扩展:该题还有两个常见的变体:
1. 从尾到头输出一个字符串;
2. 定义一个函数求字符串的长度,要求该函数体内不能声明任何变量。
给一个天平,问如何用3次把这个小球找出来
并且求出这个小球是比其他的轻还是重
将12个球分别编号为a1,a2,a3.......a10,a11,a12.
第一步:将12球分开3拨,每拨4个,a1~a4第一拨,记为b1, a5~a6第2拨,记为b2,其余第3拨,记为b3;
第二步:将b1和b2放到天平两盘上,记左盘为c1,右为c2;这时候分两中情况:
1.c1和c2平衡,此时可以确定从a1到a8都是常球;然后把c2拿空,并从c1上拿下a4,从a9到a12四球里随便取三球,假设为a9到a11,放到c2上。此时c1上是a1到a3,c2上是a9到a11。从这里又分三种情况:
A:天平平衡,很简单,说明没有放上去的a12就是异球,而到此步一共称了两次,所以将a12随便跟11个常球再称一次,也就是第三次,马上就可以确定a12是重还是轻;
B:若c1上升,则这次称说明异球为a9到a11三球中的一个,而且是比常球重。取下c1所有的球,并将a8放到c1上,将a9取下,比较a8和a11(第三次称),如果平衡则说明从c2上取下的a9是偏重异球,如果不平衡,则偏向哪盘则哪盘里放的就是偏重异球;
C:若c1下降,说明a9到a11里有一个是偏轻异球。次种情况和B类似,所以接下来的步骤照搬B就是;
2.c1和c2不平衡,这时候又分两种情况,c1上升和c1下降,但是不管哪种情况都能说明a9到a12是常球。这步是解题的关键。也是这个题最妙的地方。
A:c1上升,此时不能判断异球在哪盘也不能判断是轻还是重。取下c1中的a2到a4三球放一边,将c2中的a5和a6放到c1上,然后将常球a9放到c2上。至此,c1上是a1,a5和a6,c2上是a7,a8和a9。此时又分三中情况:
1)如果平衡,说明天平上所有的球都是常球,异球在从c1上取下a2到a4中。而且可以断定异球轻重。因为a5到a8都是常球,而第2次称的时候c1是上升的,所以a2到a4里必然有一个轻球。那么第三次称就用来从a2到a4中找到轻球。这很简单,随便拿两球放到c1和c2,平衡则剩余的为要找球,不平衡则哪边低则哪个为要找球;
2)c1仍然保持上升,则说明要么a1是要找的轻球,要么a7和a8两球中有一个是重球(这步懂吧?好好想想,很简单的。因为a9是常球,而取下的a2到a4肯定也是常球,还可以推出换盘放置的a5和a6也是常球。所以要么a1轻,要么a7或a8重)。至此,还剩一次称的机会。只需把a7和a8放上两盘,平衡则说明a1是要找的偏轻异球,如果不平衡,则哪边高说明哪个是偏重异球;
3)如果换球称第2次后天平平衡打破,并且c1降低了,这说明异球肯定在换过来的a5和a6两求中,并且异球偏重,否则天平要么平衡要么保持c1上升。确定要找球是偏重之后,将a5和a6放到两盘上称第3次根据哪边高可以判定a5和a6哪个是重球;
B:第1次称后c1是下降的,此时可以将c1看成c2,其实以后的步骤都同A,所以就不必要再重复叙述了。至此,不管情况如何,用且只用三次就能称出12个外观手感一模一样的小球中有质量不同于其他11球的偏常的球。而且在称的过程中可以判定其是偏轻还是偏重。
3.U2 合唱团在17 分钟内得赶到演唱会场,途中必需跨过一座桥,四个人从桥的同一端出发,
你得帮助他们到达另一端,天色很暗,而他们只有一只手电筒。一次同时最多可以有两人 一
起过桥,而过桥的时候必须持有手电筒,所以就得有人把手电筒带来带去,来回桥两端 。
手电筒是不能用丢的方式来传递的。四个人的步行速度各不同,若两人同行则以较慢者 的
速度为准。Bono 需花1 分钟过桥,Edge 需花2 分钟过桥,Adam需花 5 分钟过桥,Larry 需
花 10 分钟过桥。他们要如何在 17 分钟内过桥呢?(有个同济的学生写文章说他当时在微
软面 试时就是碰到了这道题,最短只能做出在 19分钟内过桥,微软的人对他讲这样的结果
已经 是不错的了!)
A点到 B 点
1 和2 过去 2 分钟 2
2 过来 4 分钟 2+2=4
10和 5过去 14 分钟 4+10=14
1 过来 15 分钟 14+1=15
1 和2 过去 17 分钟 15+2=17