阿里巴巴2017实习生招聘研发工程师C/C++笔试题,包括选择题和编程题。
一、选择题
1.(单项选择题)
下面关于C/C++的说法,正确的选项是
- A、C语言要求变量声明必须单独作为一句,然后才能使用
- B、在C风格结构体的声明中,数组成员必须总是指定一个固定大小
- C、C++的虚函数的实现机制,不能用C风格的语法来模拟
- D、同名的全局模板函数和全局普通函数,模板函数重载匹配的优先级更高
- E、STL容器的迭代器end()返回容器的最后一个元素
- F、以上都不对
答案:C
解析:
A:C语言要求变量必须先定义,然后才能使用,光声明之后是不能直接拿来用的。
B:可以不指定大小,有编译器去识别,例如char [] s={‘a’, ‘b’, ‘c’};
C:C++虚函数的实现机制在于继承体系下的动态绑定,是CPP的特性,C语法无法模拟。
D:优先调用全局的普通函数
函数模板与同名的非模板函数重载时候,调用顺序:
寻找一个参数完全匹配的函数,如果找到了就调用它
寻找一个函数模板,将其实例化,产生一个匹配的模板函数,若找到了,就调用它
若1,2都失败,再试一试低一级的对函数的重载方法,例如通过类型转换可产生参数匹配等,若找到了,就调用它
若1,2,3均未找到匹配的函数,则是一个错误的调用
E:STL容器的迭代器end()返回容器的最后一个元素后移位置的迭代器
2.(单项选择题)
答案:C
解析:
3.(单项选择题)
一个电梯载有12人从地下一层向上升,每个人都可以在电梯到达一层到五层中任意一层出电梯,到达6层时电梯已经没人了,一共有多少种出电梯的情况(每个人出了电梯不能再进,所有人看做相同人)?
- A、330
- B、495
- C、7920
- D、3960
- E、1820
- F、2380
答案:E
解析:
注意本题将所有人看做是相同的人,与常做的题“4封不同的信投往3个信箱,共有多少种投法的题不一样”。
对于本题,可以将题目转化为12个球中间插4个板,分成5份的问题,但是题意要求两个板之间的球个数可以为0,所以增加五个球,在17个球之间插四个板,答案为C(16,4)=16151413/(4321)=1820种方式。
4.(单项选择题)
请阅读下面代码,判断可被垃圾回收的对象。
public class TestGC{
private static TestGC m_t;
public static assign(TestGC t)
{
m_t=t;
}
public void clear(TestGC t)
{
t=null;
}
public static void main(String[] args)
{
TestGC t1=new TestGC();
TestGC t2=new TestGC();
TestGC t3=new TestGC();
t1.assign(t2);
t1=null;
t2=null;
t3.clear(t3);
System.out.println("This point");
}
}
当程序执行到“System.out.println("This point");”这行时,可被虚拟机回收的对象有:
- A、t1
- B、t1、t2
- C、t2、t3
- D、t1、t3
- E、t1、t2、t3
- F、t1、t2、t3全都不可回收
答案:E
解析:
在编译过程中作为一种优化技术,Java 编译器能选择给实例赋 null 值,从而标记实例为可回收。
5.(单项选择题)
请阅读下面代码,计算运行结果:
public class Person{
private int i=1;
public Person()
{
System.out.print("P");
}
public void print()
{
System.out.print(i);
}
}
public class Friend{
public Friend()
{
System.out.print("F");
}
}
public class Son extends Person{
private Friend f=new Friend();
public Son()
{
System.out.print("S");
}
public void print()
{
int i=2;
System.out.print(i);
}
public static void main(String[] args)
{
Person s=new Son();
s.print();
}
}
以上程序的运行结果是:
- A、SPF2
- B、PFS2
- C、PSF2
- D、PSF1
- E、SPF1
- F、以上都不对
答案:B
解析:
Java中构造函数的执行顺序:
- 内部静态对象的构造函数
- 父类的构造函数
- 内部普通对象的构造函数
- 该类本身的构造函数
6.(单项选择题)
请阅读下面代码,计算运行结果:
public class TestEx{
public static int test(String StrL,String StrR) throws Exception
{
int iL,iR,iRet=-1;
try{
iL=Integer.parseInt(StrL);
iR=Integer.parseInt(StrR);
iRet=iL/iR;
}catch(NumberFormatException e){
System.out.print("N");
}catch(ArithmeticException e){
System.out.print("A");
throw new Exception("Input value error");
}finally{
System.out.print("F");
}
return iRet;
}
public static void main(String[] args)
{
try{
test("100","abc");
test("5","0");
}catch(Exception e){
System.out.print("E");
}
}
}
以上程序的运行结果是
- A、NFAE
- B、NFAFE
- C、NAAE
- D、NAE
- E、NEAE
- F、以上都不对
答案:B
解析:
“test("100","abc");”执行后,“abc”转换为数字发生异常,被“catch(NumberFormatException e)”捕获,输出“N”,接下来执行“finally”块,输出“F”;test("5","0");
转换为数字正常,但是在做除法的时候发生除零异常,被“catch(ArithmeticException e)”捕获,输出“A”,接下来执行“finally”块,输出“F”。
最后,由于两个test函数被try语句块包围,而且发生了异常,会被随后的“catch(Exception e)”捕获,输出“E”。
因此,最终的输出结果为“NFAFE”,B选项正确。
7.(单项选择题)
public class TestFinally{
public static void main(String[] args) throws InterruptedException
{
Runnable s=new Runnable(){
public void run()
{
try{
System.out.print("线程开始执行");
Thread.sleep(1000);
System.out.print("线程执行完毕");
}catch(InterruptedException e){
System.out.print("睡眠中发生了中断");
}finally{
System.out.print("finally块被调用了");
}
}
};
Thread thread=new Thread(s);
thread.setDaemon(true);
thread.start();
Thread.sleep(500);
}
}
程序执行后,输出的内容最有可能是以下哪种情况:
- A、线程开始执行 线程执行完毕 睡眠中发生了中断 finally块被调用了
- B、线程开始执行 睡眠中发生了中断 finally块被调用了
- C、线程开始执行finally块被调用了
- D、线程开始执行
- E、线程开始执行 finally块被调用了 睡眠中发生了中断
- F、没有输出
答案:D
8.(单项选择题)
假设一棵高度为N的平衡二叉树,从树中随机选择一个节点,该节点为叶子节点的概率可能为
- A、100%
- B、50%
- C、60%
- D、[50%,100%]
- E、20%
- F、以上均有可能
答案:D
解析:
平衡二叉树中,叶子节点的比例最小为50%(一个根节点加一个左子节点),最大为100%(只有一个根节点)。
9.(单项选择题)
以下说法正确的是()
#include
int f(int i){
if(i<=0){
return 1;
}
return i*f(i-1);
}
int main()
{
for (size_t i = 10; i >= 0; --i)
{
std::cout<
- A、正常输出1~10的阶乘
- B、正常输出0~10的阶乘
- C、正常输出0~2^32-1的阶乘
- D、死循环
- E、编译错误
- F、运行错误
答案:D
解析:
f(i)对于i<=0时进入死循环。
10.(单项选择题)
一位阿里巴巴的员工每天8:30-9:00去上班,根据堵车情况不同大概10-30分钟到公司,假设他出门时间和路上的时间都是独立的均匀分布,他在9:00前到达公司的概率是多少?
- A、1/2
- B、1/3
- C、2/3
- D、1/4
- E、3/4
- F、7/12
答案:B
解析:
P=(1/2*20*20)/20*30=1/3
11.(单项选择题)
有一组记录排序码(1 9 6 2 5 4 7 3) 需要进行堆排序, 请问在堆化(小根堆)之后, 堆所对应的二叉树的后序遍历序列为:
- A、(9 3 2 5 1 6 4 7)
- B、(9 3 5 2 6 7 4 1)
- C、(9 2 3 1 5 4 6 7)
- D、(9 3 2 5 6 7 4 1)
- E、(9 3 2 5 6 1 4 7)
- F、(9 2 3 5 6 7 4 1)
答案:B
解析:
最小堆:先以数组顺序构建一棵完全二叉树,再从第n/2 +1个元素开始构建最小堆,再进行中序遍历。本例中就是从第5个元素5开始进行调整。具体的堆调整过程如下图(a)-(d)所示:
最终小根堆化后的序列为(1 2 4 3 5 6 7 9),对其进行后序遍历后的结果为(9 3 5 2 6 7 4 1),故而本题的B选项正确。
12.(单项选择题)
假设Linux中有个/tmp/test目录,权限为drwxrw-r--,以下描述正确的是
- A、文件的组成员能执行cd命令进入目录
- B、文件的非组成员能执行cd命令进入目录
- C、文件的组成员能执行ls命令查看该目录
- D、文件的组成员能执行touch test/a.txt来创建文件
- E、文件的非组成员能执行rm –rf /tmp/test来删除该目录
- F、文件的组成员能执行rm –rf /tmp/test来删除该目录
答案:C
解析:
文件的组成员拥有读权限,因而可以执行ls命令进行查看。
文件的组成员没有执行权限,因而无法执行A、D、F的指令操作。
文件的非组成员没有执行权限,因而无法执行B、E操作。
13.(单项选择题)
A和B两个团队在合作p项目,B团队做p项目的子项目p1,A团队做子项目p2,A和B的主管不是同一个人,后来p1项目衍生出来一个附属项目s,B团队做了一段时间后,B团队由于有其他紧急项目,B团队的主管M让B团队的兄弟团队C团队来做s项目,同时p1项目也调走了几个人,A团队不开心,这干扰了A团队在p2项目中的项目进度。而且A团队由于之前跟C团队合作不顺畅,不是很认可C团队的能力。A团队以下做法中最不恰当的是:
- A、将BC团队召集在一起沟通,让他们改变计划,确保p项目顺利完成。
- B、重新制定项目计划,引入自己认可的D团队接手B团队的所有任务。
- C、与主管M理论,要求B团队充分重视p项目,加强p2和s项目的投入,反对C团队的加入
- D、条件允许的情况下自己建团队做p2和s项目。
- E、放弃p项目,从项目中撤出所有人员,转去做其他项目。
- F、私下向大Boss告状,质疑B团队的合作精神以及C团队的能力。
答案:E
解析:
感觉F选项也不是很靠谱。
14.(单项选择题)
下列各项不属于性能关注点的是
- A、应用启动速度
- B、页面切换速度
- C、页面滑动流畅度
- D、页面跳转流畅度
- E、应用闪退
- F、应用耗电情况
答案:E
解析:
E选项属于应用异常,而不是应用性能,其他的选项都是应用的性能。
15.(单项选择题)
答案:F
解析:
16.(单项选择题)
小明的复活节礼物是4只彩蛋,每个彩蛋上写了一行字:第一个彩蛋:“所有的彩蛋中都有水果糖”;第二个彩蛋:“这个彩蛋里面有棉花糖”;第三个彩蛋:“这个彩蛋里没有巧克力”;第四个彩蛋:“有些彩蛋中没有水果糖”。如果其中只有一句真话,那么以下哪项为真?
- A、所有的菜单中都有水果糖
- B、所有的彩蛋中都没有水果糖
- C、所有的彩蛋中都没有棉花糖
- D、第三个彩蛋中有巧克力
- E、第三个彩蛋中没有巧克力
- F、第二个彩蛋中有棉花糖
答案:D
解析:
第一个彩蛋中的描述与第四个彩蛋的描述互斥,由于只有一句真话,那么真话必然在第一个彩蛋和第四个彩蛋中诞生。那么第二个彩蛋和第三个彩蛋的描述必然是假话,从而可以推出:第二个彩蛋中没有棉花糖,第三个彩蛋中有巧克力。因此本题正确的选项四D。
17.(单项选择题)
36辆赛车参加比赛,赛程车速是定值,但每个赛车车速各不相同。当前只有6个赛道,无法计时,每场只能知道6辆车的相对快慢,请问最少几场比赛可以找出36辆车速度最快的前3名?
- A、6场
- B、7场
- C、8场
- D、9场
- E、10场
- F、11场
答案:C
解析:
首先,36辆赛车分成6组赛跑,需要赛6场,每场取前三。
其次,将每组第一名拉出来跑一次,需要加赛1场,按照每组第一名的排列每组,也就是
A1 A2 A3
B1 B2 B3
C1 C2 C3
D1 D2 D3
E1 E2 E3
F1 F2 F3
此时也就是表示每一排由快到慢3个人,第一列由快到慢。总共只需要最快的三个人,4-6排都不可能,然后C2、C3也不可能,因为A1 B1 C1都比他们快,B3也不可能,因为A1 B1 B2都比他快,A1一定是最快的,OK,只剩下5个人需要比一下2、3名,再跑一次,需要加赛1场。
因此,最少需要的场次位6+1+1=8场。
18.(单项选择题)
假定存在A(mbr_id,name),B(prd_id,mbr_id,prd_name)两个表,以下六个选项的SQL的分别运行,哪个的结果与其他5项不一致?
- A、select count(distinct B.prd_id) from A,B where A.mbr_id = B.mbr_id;
- B、select count(distinct B.prd_id) from B Left outer join A ON A.mbr_id=B.mbr_id where A.mbr_id is not null
- C、select count(distinct B.prd_id) from B WHERE exits (select * from A where a.mbr_id = b.mbr_id);
- D、select count(t.prd_id) FROM (select B.prd_id from B WHERE B.mbr_id in (select mbr_id from A) group by B.prd_id);
- E、select count(distinct B.prd_id) from A Left outer join B on A.mbr_id = B.mbr_id AND A.mbr_id is null;
- F、select count(distinct B.prd_id) from A Right outer join B on A.mbr_id = B.mbr_id WHERE A.mbr_id is not null;
答案:E
解析:
考查数据库表的左连接与右连接的特性。
将E选项改为:
select count(distinct B.prd_id) from A Left outer join B on A.mbr_id = B.mbr_id AND B.mbr_id is not null;
这样,该语句就和其他语句的功能一样了。
19.(单项选择题)
设一棵完全二叉树共有799个节点,则在该二叉树中的叶子节点数为:
- A、398
- B、399
- C、400
- D、401
- E、402
- F、403
答案:C
解析:
799=1+2+4+8+16+32+64+128+256+288
因此叶子节点的个数是288+256-288/2=400
2n-1=799,则n=400
20.(单项选择题)
下面程序的输出是()
#include
class A{
public:
A(){
std::cout<<"A()"<
- A、A() B() ~A() A() B() ~B() ~A()
- B、A() B() ~B() A()B() ~B() ~A()
- C、A() B() ~B() ~A() A() B() ~B() ~A()
- D、A() B() ~A() ~B() A() B() ~A() ~B()
- E、编译错误
- F、运行错误
答案:A
解析:
1)“A *pa=new B;”
用B类初始化A类的指针,使用new创建B类对象时,由于B类公有继承自A类,因而优先调用基类A的构造函数,输出“A()”再调用子类B的构造函数,输出“B()”。在完成B类对象创建后,利用赋值语句,将创建好的B类对象用来初始化A类的指针pa,此时pa完全是一个A类的指针,与用new A创建的A类指针别无二致,加上A类的析构函数不是虚函数,不存在动态绑定的问题,因而在执行“delete pa;”语句之后,只会析构掉pa指针所指向的对象,调用A类的析构函数,输出“~A()”。
2)“B *pb=new B;”
用B类初始化B类的指针,使用new创建B类对象时,由于B类公有继承自A类,因而优先调用基类A的构造函数,输出“A()”再调用子类B的构造函数,输出“B()”。接着执行语句“delete pb”,析构掉B类指针所指向的对象,由于B类公有继承自A类,析构函数的调用顺序与构造函数相反,因而先调用B类的析构函数,输出“~B()”,再调用A类的析构函数,输出“~A()”。
二、 编程题
1. (简答题)
做股票的人总会忍不住幻想:如果知道明天怎样就好了。那么问题来了,如果打开上帝视角,你最好能做到怎样?
真实的世界的股票交易规则太复杂,我么这里做一些简化。首先我们假设有N个股票和M个交易期。可以认为在单个交易期内所有股票的价格都是恒定的。股票卖出需要缴纳交易额的P倍的印花税。股票可以零碎地买卖,即你买个0.01股也是可以的。我们这个市场没有停牌,也没有休市,没有涨涨停停,没有买空卖空,没有分红,而且股票价格也不对跌到零。
举个例子,假设你用手里的一元钱买了个股票。这个股票第一期1元/股,你买入之后手上有1股股票和0元现金。这个股票在第二期涨到2元/股,那么这时你卖出1股就获得了2元(税前),扣除10%的印花税,你手上没有股票却有1.8元现金。
如果你在一开始有1元现金,在M个交易期之后,你最多能持有多少现金?
解题思路:
要么啥都不买,要么就全都买一种股票,这样才能收益最大化。
动态规划:从第一个交易期往后递推就可以了,维护两个数组,第一个表示某交易期后可以获得的最大现金,第二个采用二维数组,表示某交易期后能够获得的某股最大股票数量。用第k-1交易期的数组值来更新第k交易期的数组值。
2.(简答题)
多多岛上有很多小火车,在提茅斯机房由燕来的放射性火车库排列改成了新的车库,每个车库只能存放一辆小火车,每个小火车进到车库只能单行。每个小火车出车库由一个天车把移动钢轨放到车库前,然后把该列上的小火车从下而上优先出库。你能帮胖总管实现火车出站调度吗?