一、简答题
1.简述数据库以及线程死锁产生的原理及必要条件,简述如何避免死锁。
2.请列举面向对象设计的三个基本要素和五个主要涉及原则。
三个基本要素:封装、继承、多态。
五个基本原则:
(1)单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。
(2)开放封闭原则:软件实体对外扩展开放,对修改封闭。
(3)里氏替换原则:子类的实例能够替换父类的实例。
(4)接口分离原则:采用多个专门的接口比使用单一的总接口要好。一个类对另一个类的
依赖性建立在最小的接口上。
(5)依赖倒置原则:依赖抽象不要依赖具体实现。、
3.简述Windows内存管理的几种方式及其优缺点。
(1)块式管理。把主存分为一大块、一大块的,当所需的程序片段不在主存时就分配一块主存空间,把程序片段加载到主存,就算所需要的程序片段只有几个字节也只能把这块分配给它。优点:易于管理;缺点:浪费空间。
(2)页式管理。把主存分为一页一页的,每一页的空间要比一块一块的空间小很多,显然这种方式的空间利用率要比块式管理高出很多。
(3)段式管理。把主存分为一段一段的,每一段的空间又要比一页一页的空间小很多,这种方法在空间利用率上比页式管理高出很多,但也有另外一个缺点,一个程序片段可能会被分为几十个段,这样很多时间就会浪费在计算每一段的物理地址上。(I/O操作)
(4)段页式管理。结合了段式管理和页式管理的优点。把主存分为若干页,每一页又分为若干段。
二、算法和程序设计
1.公司组织一次羽毛球比赛,采用淘汰机制,假设公司有1001个人,如果要评出“公司羽毛球第一高手”的称号,至少需要进行多少场比赛?请简述设计过程,并写出代码模拟比赛过程。
/*
* 分析: 我们可以分轮来比赛,每一轮都有2个人去比赛,如果总数(person)是奇数,
*
* 则有一个轮空,否则全部参与比赛,淘汰一半(person/2),剩余[person/2)+remain],
*
* 这里,remain=person%2.,淘汰的人数亦即比赛的场数,加起来就构成了比赛场
*
* 数。
*/
public static void main(String[] args) {
int person = 1001; //当然person一般是由用户来输入的。
int result = 0, remain;
while (person > 0 && person != 1) {
result += person / 2; // 进行了比赛==淘汰的人数
remain = person % 2; // 有没有人轮空
person /= 2; // 比赛后剩余的人数
person += remain; // 要加上轮空的人
}
System.out.println("共进行:" + result + "场比赛");
}
2.一百个灯泡排成一排,第一轮将所有灯泡打开;第二轮每隔一个灯泡关掉一个。即排在偶
数的灯泡被关掉,第三轮每隔两个灯泡,将开着的灯泡关掉,关掉的灯泡打开。依次类推,第100轮结束的时候,还有几盏灯泡亮着。
//哈哈,这道题是在宁波实习的时候有个网友问我的,不几天后就看到百度笔试有这道题,.
//真神奇啊!
//分析:
所有的台灯,只有摁下的次数是奇数,那么它一定是打开的,而对于台灯X,如果其前面有基数个X的约数,例如:
4=1*2*4
9=1*3*9
16=1*2*4*8*16
而6=1*2*3*6 //偶数
因此,1~100内,查找X的约数个数为奇数的数X即为开着的台灯。
public static void main(String[] args) {
//编码就很简单了.
for(int i=1;i<100;i++){
if(hasOddOddNumer(i)){
System.out.print(" "+i);
}
}
}
private static boolean hasOddOddNumer(int data) {
boolean result = false;
int approximateNumberCount = 0;
for (int i = 1; i <= data; i++) {
if (0 == data % i) {
approximateNumberCount++;
}
}
if (0 != approximateNumberCount % 2) {
result = true;
}
return result;
}
3.假定有20个有序数组,每个数组有500个数字,数字类型32位uint数值,现在需要取出
这10000个数字中最大的500个,怎么做?
额,这个我看了别人给的方案,发现自己想错了,仅贴出别人的算法:
从20个数组中各取一个数,并记录每个数的来源数组,建立一个含20个元素的大根堆。
此时堆顶就是最大的数,取出堆顶元素,并从堆顶元素的来源数组中取下一个数加入堆,再取最大值,一直这样进行500次即可。
时间复杂度:500*log2(20)
三、系统设计题
手机上通常采用九键键盘输入。即:1-9个数字分别对应一定的英文字母(如:2对应ABC,
3对应DEF,...),因此,用户可以方便的输入中文内容。比如,用户输入“926”,可以对应
“WXYZ”,“ABC"和”MNO“的一系列组合”WAN”,“YAN"、”ZAO“等,这些对应“万”,“严”,“早”
等汉字的中文拼音。
要求我们把这样的输入方式应用在我们的手机联系人查找功能上。有一个联系人列表
UserList,记录了(姓名,手机号)这样的组合,通过输入的数字字符串NumStr,按照下面
的规则把对应的联系人查找出来,返回一个ReaultList。
规则:
1.手机号能连续部分匹配输入的数字字符串NumStr。如输入NumStr=926,则手机号为
13926811111会被查出来;
2.联系人姓名中的汉字转化成拼音后能够连续匹配输入数字字符串NumStr对应的英文字母
组合,如:输入NumStr=926,则联系人“王二”、“万事通”会被查找出来。因为“王二”的“王”的
拼音“WANG”中含有“WAN”,和“926”能匹配。
输入:
联系人列表UserList<UserName, PhoneNo>;汉字拼音射射表Dict,数字拼音字符串
NumStr。
输出:
符合规则的联系人列表ResultList<UserName, PhoneNo>。
/*
对于这种题,我不知道考察的是什么,其实我们应该可以*假设自己的条件吧,然后根据自己的步骤来做出判断,下面是我的一个思路,这个真不知道怎么样,还请高手们 不要笑话。
*/
设Phone phoneList<UserName, PhoneNo>存储了所有联系人的信息;
首先,我们获取“926”对应的所有拼音可能组成一个列表:
List<String> inputNameList=new ArrayList<String> ();
然后,把用户输入的字符串的所有可能add到inputNameList。例如,9,2,6就有3*3*3种可能都add到inputNameList里面。
根据需求,用户名和手机号关键字都可能存在满足条件的情况,所以我们在一次遍历phoneList的情况下分别判断: (假设ResultList已经初始化,这里不再做实例化)
for(Phone aPhone:phoneList ){
//电话号码中是否含有字串 “926”
if(-1!=aPhone.getPhoneNo().indexOf(NumStr)){
ResultList.add(aPhone);
}
//我们根据姓获取姓的拼音aDict,然后遍历
//这个表,同样用字串截取的办法来判别。
String aDict=aPhone.getUserName().getDict();
for(String indexName :inputNameList){
If(-1!=aDict.indexOf(indexName )){
ResultList.add(aPhone);
}
}
}
这样,这个ResultList就找到了。