09金山实习生笔试总结

首先说一点,感觉金山对这次实习生很不重视,连个工作人员都没派来,监考是学院的人,很囧。也没看到保密协定,所以就公开这篇日记了。
第一题是求两个整数区间的交集,即[a,b]和[c,d]的交集。这题目很简单,只要讨论端点的大小就好了。
第二题,给一个只包含字母和空格的字符串,不区分大小写,然后问那个字母没有出现过?这题目更简单,建立一个26个字母的标记表,初始化时全设置为FALSE,然后扫描字符串,出现过的字母设置为TRUE。扫描结束后再扫描一次标记表,还是FALSE的表明没有出现过。
第三题,斐波那契数列问题:
F(0)=0;F(1)=F(2)=1;F(n)=F(n-1)+F(n-2);(n>=3)。现在定义:
int v=F(n);求在v不溢出的情况下,n的最大值。
没有想到比较快的方法,就是从F(3)起开始求,判断当前值是否超过int的最大值,溢出后就结束。不过,斐波那契数列增长很快,求这个的速度不会很慢。我写的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "iostream"
#include "cmath"
#include "cstdlib"
using namespace std;
 
int main(){
 
	int n=3;
 
	unsigned int a=1,b=1,c=2;//a保存F(n-2),b保存F(n-1),c保存F(n)
 
	unsigned int MaxInt=pow(2.0,31)-1;
 
	while(c<MaxInt){
		c=a+b;
		a=b;
		b=c;
 
		++n;
	}
 
	cout <<n<<endl;
	system("pause");
	return 0;
}

运行不到1秒钟,结果为48.当时我笔试的时候犯了个低级错误,int型的最大值是2^31-1而不是2^32-1(unsigned int类型)。
第四题,哥德巴赫猜想,一个偶数必然可以表示成两个素数之和。那么现在给一个N(4<=N<=1000),求N可被表示为不同的两个素数对的个数。比如20,可以表示为(3,17)和(7,13)两对.思路也比较简单,打个素数表,然后在[2,N/2]之间的素数判断,假设当前值为i,只要判断N-i是否为素数就可以了.代码不贴了.
第五题还不错.问析构函数用虚函数有什么作用?举个例子说明这点.我对虚函数了解不多,当时感觉可能造成内存泄漏,然后就糊弄着写了下.回来后Sandy给我讲了下,才渐渐明了.
首先应该知道一点,析构函数不必要是虚函数.
其次,考虑两个问题,(1)析构函数为什么要声明为虚函数?在什么地方需要? (2)为什么析构函数要层层由子类向基类析构?
先看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class sth
{
public:
	~sth(){printf("sth freed.
");}
};
 
class A{
 
public:
	A(int a1):a(a1){s1=new sth();}
	virtual ~A(){printf("A:%d  destroyed
",a);}
	virtual void F(){printf(" A(%d)::F called 
",a);delete s1;}
	int a;
	sth *s1;
};
 
class B : public A{
public :
	B(int a1):A(a1){s2=new sth();}
	virtual ~B(){printf("B:%d  destroyed
",a);}
	virtual void F(){printf(" B(%d)::F called 
",a);delete s2;}
	sth *s2;
};
 
int test()
{
	A a1(1);
	B b1(2);
	A *a2;
	a2=new B(3);
	//a2->F();
	delete a2;
 
	return 0;
}

如果不将class A的析构函数声明为虚函数,那么当声明一个A *a2;时,系统知道a2是指向A对象的指针,但是你又a2=new B(3);那系统是不会知道a2实际指向了B的.此时如果delete a2时,系统只会调用A的析构函数.这就是释放一半留一半,内存泄漏了.
系统在有虚函数的时候,会建立一个虚函数表,这个表中就是一些函数指针.当a2=new B(3)时,此时a2就是指向了B的对象,因此会调用B的析构函数.
那么为什么要层层向上级析构呢? 因为每一层只管理当前层的数据的释放.虽然子类知道父类分配了些内存,但是却不知道怎么释放,或者说这事不用他管.只要层层回调析构,就可以达到释放所分配的内存.这个过程跟子类的构造函数的过程正好相反.构造函数是由基类向子类层层构造.

总结:虽然这次笔试难度很低,不过还是学到了些东西.一个是要细心,基础的概念要扎扎实实的,以后还有类似unsigned和int之类的问题.另一个是C++不仅要看,而且要多写.之前看过很多遍虚函数,换个问题就没思路了.

5 Comments are ready?

  1. Felix021 said on: 2009年06月25日 23:07

    第一个程序非常值得推敲阿。问题很多。

    关于虚析构函数,可以参见Effective C++ Item 7。

    [回复]

    boluor 回复  于   

    这题就是比较啰嗦…我花了大致上十几分钟来分类讨论.

    Effective C++上那张看了.我觉得主要是我写的少.

    [回复]

    littlekid 回复  于   

    也可以参考Ruminations on C++相应条目~

    [回复]

  2. Sandy said on: 2009年06月26日 20:57

    unsigned int MaxInt=pow(2.0,31)-1;
    ……这句也太囧了吧……………………(我估计阅卷的看到了都囧了)
    你忘了你之前整理的那些位运算基础知识了么?
    直白的写法: const unsigned int maxInt=~((unsigned int)0);
    精简的写法:#define MAXINT (-1)
    标准的写法:std::numeric_limits::max();
    怎么着都轮不到动用浮点数去搞吧……
    基础啊基础

    [回复]

    Sandy 回复  于   

    靠,你的blog把我的template吃了……
    std::numeric_limits<unsigned int >::max()
    试试这个……

    [回复]

    Sandy 回复  于   

    果然,非得我去打那个“&lt;”这种html转义码才可以保证大于号小于号不被吃……这个wordpress转义做得太cuo了吧……

    [回复]

    boluor 回复  于   

    确实很囧…
    这题不错^.^

    [回复]

  3. littlekid said on: 2009年06月26日 21:55

    shit!
    这题我看到过三次,第一次帮别人做(做进去了),第二次自己做(挂了),果然你们又考了一样的题目~~

    [回复]

    boluor 回复  于   

    所以说金山很不重视嘛…明天给面试通知,去玩玩好啦

    [回复]

  4. abioy said on: 2009年07月9日 00:10

    >._<

    [回复]

  5. abioy said on: 2009年07月9日 00:11

    我们的出了连分数。笔试之前搜到的都很简单,我就很放心地把浏览器关掉,快到时间才回来笔试,没想到出了一道数论的东东-_-,打我弱点。做到傻了连暴力都不敲,直接空了那题。
    原来要转义才能看到的

    [回复]

    boluor 回复  于   

    连分数题目咋出的?

    [回复]

Post a Comment

Your email is never published nor shared. Required fields are marked *

*

*