作者:寒小陽
時間:2013年9月。
出處:http://blog.csdn.net/han_xiaoyang/article/details/11533437。
聲明:版權所有,轉載請註明出處,謝謝。
前言:
今年迅雷依舊是動作很快的公司之一,才9月初就已經筆試完了,看來還是想趕在互聯網公司招聘大潮前搶些人。雖然傳聞迅雷工作挺累的,然後待遇一般(不確定數據可靠度有多高,不過都說根據水平不同,研發base高的差不多騰訊的水平,低的不過萬),但是宣講會和筆試的時間早,肯定和去年一樣還是人山人海,也不乏大牛們過去練練手。不過maybe明年會上市吧,恩,這個對很多人還是有吸引力的。好吧,胡說八道閒扯一大堆,進入正題吧。把這幾年(包括今年)的迅雷筆試題拿來揉了揉,放在一起,我們看看他家都考察些什麼,這類公司需要做些什麼準備吧。
先上題吧,我會對每道題稍加解釋一下(當然,本人水平很菜,若有不當之處,請大家指出);題目和答案過後,本文最後我會對考點總結匯總一下。
兩年前的筆試題:
一、選擇題
1.下列程序的輸出結果爲:(B)
#include<iostream.h>
void main()
{
char* a[ ] = { "hello", "the", "world"};
char** pa = a;
pa++;
cout<<”*pa<<endl;
}
A) theworld B) the C) ello D) ellotheworld
分析:a是指針的數組
char** p = a; //char** p = &a[0]
p++;//p是指針自增+4,而a中元素是指針,每個正好四個字節,因此p++後恰好p= &a[1]
*p=a[1];輸出"the",輸出結果爲B
2. 已知二叉樹後序遍歷序列是bfegcda,中序遍歷序列是badefcg,它的前序遍歷序列是:(B)
A) abcdefg B) abdcefg C) adbcfeg D) abecdfg
分析:很有代表性的一道題目,去年參加微軟筆試的時候也有類似的題目。後序遍歷中的最後一個元素是根節點,a,然後查找中序中a的位置,把中序遍歷分成 b a defcg,易知左子樹爲b,右子樹爲defcg,再遞歸求解,可畫出原始二叉樹,故知前序遍歷序列爲B。
3. 棧和隊列的共同特點是:(C)
A) 都是先進先出 B) 都是先進後出
C) 只允許在端點處插入和刪除元素 D) 沒有共同點
分析:基礎題,不解釋-_-||
4. 下面程序的運行結果爲:(A)
#include <iostream.h>
void main()
{
int a, x;
for(a = 0, x = 0; a<=1 && !x++; a++)
{
a++;
}
cout<< a << x <<endl;
}
A) 21 B) 22 C) 32 D) 41
5. 下列選項,不正確的是:(B)
A) for(int a=1; a<=10; a++);
B) int a=1;
do
{
a++;
}while(a<=10)
C) int a=1;
while(a<=10)
{
a++;
}
D) for(int a= 1; a<=10; a++)a++;
分析:個人認爲意義不大的一道題,考察程序語句是否書寫正確,B選項的while後沒有分號。
6. 下面關於數組的初始化正確的是:(B)
A) char str[2] = {“a”,”b”};
B) char str[2][3]={“a”,”b”};
C) char str[2][3]={{‘a’,’b’},{‘e’,’d’},{‘e’,’f’}};
D) char str[] = {“a”, “b”};
分析:A中字符變量不能存放字符串,C中維度錯了,D和A的問題一樣
7. 下列說法正確的是:(B)
A) 內聯函數在運行時是將該函數的目標代碼插入每個調用該函數的地方
B) 內聯函數在編譯時是將該函數的目標代碼插入每個調用該函數的地方
C) 類的內聯函數必須在類體內定義
D) 類的內聯函數必須在類體外通過關鍵字inline定義
8.下面對靜態成員的描述中,正確的是:(D)
A) 靜態數據成員可以在類體內初始化
B) 靜態數據成員不可以被類的對象調用
C) 靜態數據成員不能受private控制符的作用
D) 靜態數據成員可以直接用類名調用
9. 下列運算符中,在C++語言中不能重載的是:(C)
A) * B) >= C) :: D) delete
分析:詳見找工作筆試面試那些事兒(4)---C++函數高級特徵
10 下面關於多態性的描述,錯誤的是:(C)
A) C++語言的多態性分爲編譯時的多態性和運行時的多態性
B) 編譯時的多態性可通過函數重載實現
C) 運行時的多態性可通過模板和虛函數實現
D) 實現運行時多態性的機制稱爲動態綁定
分析:模板的是編譯時多態性,而虛函數是運行時。
11. 如果進棧序列爲e1,e2,e3,e4,e5,則可能的出棧序列是:(D)
A) e3,e2,e5,e4,e1
B) e2,e3,e5,e4,e1
C) e3,e2,e4,e5,e1
D) 以上都有可能
分析:經常考的一道題,去年微軟筆試也考了類似的題目。A爲e1入,e2入,e3入,e3出,e2出,e4入,e5入,e5出,e4出,e1出;B爲e1入,e2入,e2出,e3入,e3出,e4入,e5入,e5出,e4出,e1出;C爲e1入,e2入,e3入,e3出,e2出,e4入,e4出,e5入,e5出,e1出。
12 下面關於類和對象的描述中,錯誤的是:(A)
A) 類就是C語言中的結構體類型,對象就是C語言中的結構體變量
B) 類和對象之間的關係是抽象和具體的關係
C) 對象是類的實例,一個對象必須屬於一個已知的類
D) 類是具有共同行爲的若干對象的統一描述體
13.下面關於數組的描述錯誤的是:(CD)?
A) 在C++語言中數組的名字就是指向該數組第一個元素的指針
B) 長度爲n的數組,下標的範圍是0-n-1
C) 數組的大小必須在編譯是確定
D) 數組只能通過值參數和引用參數兩種方式傳遞給函數
說明:感謝@Emiyasstar__童鞋的指正,關於C選項,C99中提到了variable length arrays的概念,允許在編譯時不指定數組大小,而在運行時才確定,詳見http://www.cppblog.com/Walker/articles/80805.html。所以嚴格來說,本題C和D都是錯的。
14. 引用標準庫時,下面的說法你認爲哪個是正確的:(B)
A) 語句#include “stdlib.h”是正確的,但會影響程序的執行速度
B) 語句#include <stdlib.h>是正確的,而且程序執行速度比#include “stdlib.h”要快
C) 語句#include <stdlib.h>和#include “stdlib.h”都是正確的,程序執行速度沒有區別
D) 語句#include “stdlib.h”是錯誤的
分析:include ""是先從本地目錄開始尋找,然後去尋找系統路徑,而Include<> 相反先從系統目錄,後從本地目錄。
15.設a、b、c、d、m、n均爲int型變量,且a=5、b=6、c=7、d=8、m=2、n=2,則邏輯表達式(m=a>b)&&(n=c>d)運算後,n的值爲:(C)
A) 0 B) 1 C) 2 D) 7
分析:m=a>b後m=0,表達式爲假,&&後半部分不會操作,因此n爲初始值2
16.不能作爲重載函數的調用的依據是:(C)
A) 參數個數 B) 參數類型
C) 函數類型 D) 函數名稱
17.下列程序的輸出結果爲: (D)
#include< iostream. h>
int func(int n)
{
if〔n<1)return 1;
else return n+func(n-1);
return 0;
}
void main()
{
cout<<func(5)<<endl;
}
A) 0 B)10 C)15 D)16
18.建立派生類對象時,3種構造函數分別是a(基類的構造函數)、b(成員對象的構造函數)、c(派生類的構造函數)這3種構造函數的調用順序爲: (A)
A)abc B)acb
C)cab D)cba
19. 如果友元函數重載一個運算符時,其參數表中沒有任何參數則說明該運算符是:(D)
A)一元運算符 B)二元運算符
C)選項A)和選項B)都可能 D)重載錯誤
分析:C++中用友元函數重載運算符至少有一個參數,重載一目運算符要有一個參數,重載二目運算符要有兩個參數。
20. 有以下程序段:(D)
#define F(X,Y) (X)-- (Y)++ (X)*(Y);
…
int i, a = 3, b = 4;
for( i = 0; i<5; i++) F(a,b)
printf(“%d, %d”, a, b);
輸出結果是:()
A) 3, 4 B) 3, 5
C) -2, 5 D) -2, 9
21. 下列for循環的循環體執行次數爲:(C)
for(int i(10), j(1); i=j=0; i++, j--)
A) 0; B) 1; C) 無限; D)以上都不對
分析:賦值語句判斷爲真,一直執行
22. 下面程序的輸出結果是(D)
char *p1= “123”, *p2 = “ABC”, str[50]= "xyz";
strcpy(str+2,strcat(p1,p2));
cout << str;
A)xyz123ABC B)z123ABC
C)xy123ABC D)出錯
分析:p1和p2指向的是常量存儲區的字符串常量,沒法連接,會有問題
23.下面函數的執行結果是輸出(B)
char str[ ] = “xunlei”;
char *p = str;
int n = 10;
printf(“%d, %d, %d/n”, sizeof(str), sizeof(p), sizeof(n));
A) 4, 4, 4 B) 7, 4, 4
C) 6, 4, 4 D) 6, 6, 4
分析:sizeof的問題,詳見找工作筆試面試那些事兒(3)---內存管理那些事
33. 有下列程序段:
char *p, *q;
p = (char*) malloc(sizeof(char) * 20);
q = p;
scanf(“%s %s”, p, q);
printf(“%s %s/n”, p, q);
若從鍵盤輸入:abc def, 則輸出結果是(A)
A) def def B) abc def
C) abc d D) d d
分析:q=p;因此p,q指向的是同一段內存.scanf先是把abc寫到p指向的空間,再把def寫到q指向的空間,也就是同一段空間,因此abc被def覆蓋了。
34.現在有以下語句:
struct _THUNDER{
int iVersion;
char cTag;
char cAdv;
int iUser;
char cEnd;
}Thunder;
int sz = sizeof(Thunder);
則執行後,變量sz的值將得到(D)
A) 11 B) 12 C) 13 D) 16
分析:內存對齊問題,相關知識可參考http://blog.chinaunix.net/uid-10995602-id-2918694.html
35. 有如下程序段:
void GetMemeory(char* p)
{
p = (char*) malloc (100);
}
void test()
{
char *str=NULL;
GetMemory(str);
strcpy(str,”Thunder”);
strcat(str+2, “Downloader”);
printf(str);
}
請問運行Test函數結果是:(D)
A) Thunder Downloader B) under Downloader
C) Thunderownloader D) 程序崩潰
分析:在函數中給指針分配空間,實際上是給指針的臨時變量分配空間,函數結束後,這個臨時變量也消亡,而str仍然爲NULL,沒有爲其分配空間,此時strcpy()是肯定會出錯的。可參考找工作筆試面試那些事兒(3)---內存管理那些事
36. 函數調用exec((v1,v2), (v3,v4,v5),v6,v7);中,實參的個數是(A)
A) 4 B) 5 C) 6 D) 7
37. p是指向類X的成員m的指針,s是類X的一個對象。現要給m賦值,(C)是正確的。
A) s.p = 5 B) s->p = 5
C) s.*p = 5 D) *s.p = 5
38. 函數fun(char* p) { return p;}的返回值是(B)
A)無確切值 B) 行參p中存放的地址值
C) 一個臨時存儲單元的地址 D) 行參p自身的地址值
分析:可參考找工作筆試面試那些事兒(3)---內存管理那些事,返回的是形參p中存放的地址值。
39.a,b均爲不等於0的整形變量,以下關係式恆成立的是:(C)
A) a*b/a*b == 1 B) a/b*b/a == 1
C) a/b*b + a%b == a D) a/b*b == a
40. 設有如下說明:
typedef struct ST{ long a; int b; char c[2]; } NEW;
則下面敘述中正確的是:(C)
A)以上的說明形式非法 B)ST是一個結構體類型
C)NEW是一個結構體類型 D)NEW是一個結構體變量
41. 下列表達式正確的是:(C)
A) 9++ B) (x+y)++ C) c+++c+++c++ D) ++(a-b--)
42.在int b[ ][3] = {{1},{3,2},{4,5,6},{0}};中,sizeof(b) = (D)
A) 4 B) 12 C) 28 D) 48
43.以下程序的輸出結果是:(D)
#define M(x,y,z) x*y+z
main()
{
int a=1, b=2, c=3;
printf(“%d/n”,M(a+b,b+c,c+a));
}
A)19 B) 17 C) 15 D) 12
分析:#define的邊際效應,直接展開,變成a+b*b+c+c+a,詳見找工作筆試面試那些事兒(1)---C,C++基礎和編程風格(2)
44.若有以下定義和語句:
int u=010, v= 0x10, w=10;
printf(“%d,%d,%d/n”,u,v,w);
則輸出結果是:(A)
A)8,16,10 B)10,10,10 C)8,8,10 D)8,10,10
分析:各種進制之間的轉換,簡單題,0x表示十六進制,0表示八進制。
45. 下面程序段的輸出結果是:(B)
int a=5, b=4, c=3, d=2;
if(a>b>c)
printf(“%d/n”,d);
else if((c-1>=d)==1)
printf(“%d/n”, d+1);
else
printf(“%d/n”, d+1);
A) 2 B) 3 C) 4 D) 編譯錯誤
46.有如下程序段,請問k的值是:(D)
enum {a, b=5, c, d=4, e} k; k =c;
A) 3 B)4 C) 5 D) 6
47.有如下程序段:
int i, n = 0;
double x = 1, y1 = 2.1/1.9, y2 = 1.9/2.1;
for( i = 1; i<22; i++)
x = x*y1;
while( x!=1.0)
{
x =x*y2;
n++;
}
printf(“%d/n”, n);
請問執行結果是:(C)
A) 21 B) 22 C)無限循環 D) 程序崩潰
分析:浮點數的比較不可以用 = = 或者 != ,詳見找工作筆試面試那些事兒(1)---C,C++基礎和編程風格(2) ,會一直循環下去,選擇C
48. 用樹形結構表示實體之間聯繫的模型是(C)
A) 關係模型 B) 網狀模型 C) 層次模型 D)以上三個都是
49.有如下程序段:
char fun(char *);
main()
{
char *s = “one”, a[5] = {0}, (*f1)(char *) = fun, ch;
}
則對函數fun的調用語句正確的是(C)
A) *f1(&a); B) f1(*s); C) f1(&ch) D) ch = *f1(s);要改成(*f1)(s)才正確
50.有如下程序段:
int c = 23;
printf(“%d/n”, c&c);
請問執行結果是:(C)
A) 0 B) 46 C) 23 D) 以上都不對
二、填空題
1、下面的程序可以從1....n中隨機輸出m個不重複的數。請填空
knuth(int n, int m)
{
srand((unsigned int)time(0));
for (int i=0; i<n; i++)
if ( rand()%(n-i)<m )
{
cout<<i<<endl;
m-- ;
}
}
分析:1)由題意m必定小於n,從0至n-1中找出m個隨機數,那麼這n個數可以分爲兩組:要求的不重複的隨機數(m個)+非要求的隨機數(n-m個);i不斷自增,n-i不斷自減,所以 rand()%(n-i)最終會爲0,而每得出一個要求的不重複的隨機數,m自減,所以m最終也爲零,所以當一共得帶來m個要求數,循環會停止;if判斷i是否爲隨機數的依據是rand()%(n-i)和m相比,可能是大於,也可能是小於,結果是隨機的,而每個數符合條件的概率是m/n。
2)不過這裏要提一下,這道題的這種答案本身也是有爭議的,這種方法看似利用序號不重複原理實現隨機數的不重複,但是當n=m時,將產生順序數而不是隨機數!看似巧妙卻不符合要求,而且在n>>m時,其最先出現的值幾乎鐵定是0,1尤其是n=2m時,更是如此。
3)水平有限,暫時想不出比較合理的答案,大家有好方法歡迎留言指教,非常感謝
2、 prim函數的功能是分解質因數。請填空
void prim(int m, int n)
{
if (m>n)
{
while ( m%n ) n++;
m/=n ;
prim(m,n);
cout<<n<<endl;
}
}
分析:不整除就逐一增加除數,整除的話輸出除數,然後再遞歸求解商的質因數。
3、下面程序的功能是輸出數組的全排列。請填空
void perm(int list[], int k, int m)
{
if ( k==m )
{
copy(list,list+m,ostream_iterator<int>(cout," "));
cout<<endl;
return;
}
for (int i=k; i<=m; i++)
{
swap(&list[k],&list[i]);
perm(list,k+1,m) ;
swap(&list[k],&list[i]);
}
}
分析:這也是一道利用遞歸完成的題目了(遞歸真的是在各種筆試面試題裏屢試不爽啊!),100題和《劍指offer》裏面的典型題,全排列可以看做第一個位置上的數把整個數組裏的數取一遍(這裏用交換實現的),然後固定第一個位置,後m-1個數的全排列情況數。
三、解答題
1、用戶啓動迅雷時,服務器會以uid,login_time,logout_time的形式記錄用戶的在線時間;用戶在使用迅雷下載時,服務器會以taskid,start_time,finish_time的形式記錄任務的開始時間和結束時間。有效下載時間是指用戶在開始時間和結束時間之間的在線時間,由於用戶可能在下載的時候退出迅雷,因此有效下載時間並非finish_time和start_time之差。假設登錄記錄保存在login.txt中,每一行代表用戶的上下線記錄;下載記錄保存在task.txt中,每一行代表一個任務記錄,記錄的字段之間以空格分開。計算每個用戶的有效下載時間和總在線時間的比例。
分析:尷尬的是,博主自己對這道題,也寫不出個確定的答案,所以這裏貼一貼當時大家討論的結果,大家有好的思路想法歡迎留言指正。
@qq120848369 沒看懂,應該就是Map做個< Uid,vector< pair<int,int> > >的映射
@yby4769250 我也是想到map,轉換成數學問題的話,就是線段問題了,但是,要對用戶的所有task做一些邏輯時序合併,處理才能形成一個個線段,假如task1爲[1,5],task2爲[4,7],這個時候,在時序上,task1和task2有重疊,需要處理重疊位置,做合併,有效時序其實爲task[1,7],處理重疊問題倒是有幾個方法,可以直接轉換爲線段重疊,然後,算每段實線的和,就是全部的有效下載時間,這個貌似用可以用線段樹來做
@yby4769250
題意就是要求所有有效下載時間之和,當時時間緊迫沒想那麼多,現在想想,其實,用一個棧就能非常容易的完成,非常類似於括號匹配的做法。這裏仍然考慮到時序重合覆蓋(就像括號嵌套)的問題。
例如下面的棧:
t0_s|t0_f|t1_s|t2_s|t3_s|t3_f|t2_f|t1_f|t4_s|t5_s|t4_f|t5_f
| ((())) || ( { ) } |
這裏像括號嵌套 這裏像括號交叉
//t0_s表示task0的開始時間,t0_f表示task0的結束時間
棧元素
struct Node
{
char flag; //標記tv是開始時間還是結束時間
unsigned int tv; //時間值
};
把每一個task的按照start_time和finish_time的順序壓棧,並標記flag的值,形成上述棧,從棧頂開始彈棧,每一個f必然需要一個s匹配,如果一個f的下一個元素仍然是f,則這裏出現嵌套,則把f壓棧,直到遇到s,彈出f,計算最後一個f和s的值作爲有效值(就像只需要最外層括號)。當出現上述棧中括號交叉時,其實根本不需要特殊處理,仍然當做嵌套處理,只不過是,這個時候把{)這兩個匹配的括號,即把task的起止時間變換掉,方便處理。
2、在8X8的棋盤上分佈着n個騎士,他們想約在某一個格中聚會。騎士每天可以像國際象棋中的馬那樣移動一次,可以從中間像8個方向移動(當然不能走出棋盤),請計算n個騎士的最早聚會地點和要走多少天。要求儘早聚會,且n個人走的總步數最少,先到聚會地點的騎士可以不再移動等待其他的騎士。
從鍵盤輸入n(0<n<=64),然後一次輸入n個騎士的初始位置xi,yi(0<=xi,yi<=7)。屏幕輸出以空格分隔的三個數,分別爲聚會點(x,y)以及走的天數.
分析:同上題,丟些討論在下面吧,大家有什麼好的解法,非常歡迎留言指教,謝謝大家了!
@failuer 貪心法不可以嗎?每個騎士都最短時間到聚會地點,這樣總天數應該就是最少的了。沒下過象棋,是不是同一個地方不能同時有兩個騎士?這樣的話就需要考慮避免位置衝突的情況了。
@qq120848369 很明顯就是雙向廣搜的擴展問題麼,現在只不過是K個騎士同步做廣搜,核心算法如下:
1)每一輪循環中,每個騎士做一步擴展的廣搜,每個騎士有自己的標記(表示自己是否走過某個格子),每個騎士有自己的廣搜隊列. 所有騎士共享的是一張地圖以及每個地圖當前有幾個騎士走過.
2)隨着每一輪循環,如果在做某個騎士的一步廣搜的時候,會給每個這一步到達的格子的全局共享地圖的計數+1,立即判斷這些格子的計數是否爲K,如果是,那麼說明找到了,就是這個格子可以讓所有的騎士走最少的步到達
@Kevin_qing 1).求n個點座標平均值。 記爲點c. 2).計算c到各點距離和d0 ,計算點c周圍8個點到各點距離d。 如果某個點d<d0,則繼續往該方向搜索。 3).搜索到某個點d0<周圍8個點時得知結果
1)棋盤上面一個騎士的位置爲(x,y),到棋盤上面一個位置(x0,y0)。需要走多少步的計算公式是:MAX(ABSOLUTE(x-x0), ABSOLUTE(y-y0)); ABSOLUTE是取絕對值,MAX是求最大值。
2)棋盤上面,假設我們有兩個騎士,騎士A位置(xa,ya),騎士B位置(xb,yb);根據1我們能知道從一個騎士走到另外一個騎士需要走多少步,然後這個步數除以2 就能得到他們走多少步就能相聚(分別走),相聚地點的計算,也就是這兩個騎士的中間點。當然這個中間點可能是有多個的。
例如 xa=0,ya=0, xb=7,yb=7.能得到的可能的相聚地點 就是(3,3),(3,4),(4,3),(4,4).然後把去計算所有騎士走道這些可能的相聚地點所需要的時間,那個相聚點,騎士所需要走的總天數最小。。。。。
- #include <iostream>
- using namespace std;
- #define MAX(a, b) ( (a) > (b) ? (a) : (b) )
- #define ABSOLUTE(a) ( (a) > 0 ? a : -(a) )
- struct KnightPt
- {
- int x;
- int y;
- };
- int knightNumber = 0;//騎士個數
- int minGatherDays = 0;//相聚天數
- int minWalkDay = 0;
- int possibleGatherPtNumber = 0;//相聚地點可能是多個點(1~4),可能相聚地點的個數
- int gatherDays[4] = {0};
- int walkDays[4] = {0};//每個可能相聚地點的相聚天數
- KnightPt kinghtPt[64] = {0};//所有騎士的位置
- KnightPt possibleGatherPt[4] = {0};//可能相聚地點的集合
- //獲取騎士可能相聚的地點的集合
- void getPossibleGatherPoint()
- {
- int minXPt = 8, minYPt = 8, maxXPt = 0, maxYPt = 0;
- //根據所有騎士的位置,騎士位置X方向最小值和最大值,Y方向最小值和最大值
- for(int i = 0; i < knightNumber; i++)
- {
- if(kinghtPt[i].x < minXPt) minXPt = kinghtPt[i].x;
- if(kinghtPt[i].y < minYPt) minYPt = kinghtPt[i].y;
- if(kinghtPt[i].x > maxXPt) maxXPt = kinghtPt[i].x;
- if(kinghtPt[i].y > maxYPt) maxYPt = kinghtPt[i].y;
- }
- //計算X方向最小值和X方向最大值的中間點,使用float數據類型是因爲可能中間點處於棋盤線上。
- //例如X方向最小值爲0,X方向最大值爲7,中間值就是3.5,位於棋盤線上。同樣Y方向同樣處理
- float midXPt = minXPt + (float)(maxXPt - minXPt) / 2;
- float midYPt = minYPt + (float)(maxYPt - minYPt) / 2;
- int midXPt0 = (int)midXPt;
- int midXPt1 = (int)(midXPt + 0.5);
- int midYPt0 = (int)midYPt;
- int midYPt1 = (int)(midYPt + 0.5);
- //根據得到的中間點,計算出可能的位置(最多4個),他們都有可能是相聚點。
- possibleGatherPt[possibleGatherPtNumber].x = midXPt0;
- possibleGatherPt[possibleGatherPtNumber].y = midYPt0;
- possibleGatherPtNumber++;
- if(midXPt0 != midXPt1)
- {
- possibleGatherPt[possibleGatherPtNumber].x = midXPt1;
- possibleGatherPt[possibleGatherPtNumber].y = midYPt0;
- possibleGatherPtNumber++;
- }
- if(midYPt0 != midYPt1)
- {
- possibleGatherPt[possibleGatherPtNumber].x = midXPt0;
- possibleGatherPt[possibleGatherPtNumber].y = midYPt1;
- possibleGatherPtNumber++;
- }
- if(midXPt0 != midXPt1 && midYPt0 != midYPt1)
- {
- possibleGatherPt[possibleGatherPtNumber].x = midXPt1;
- possibleGatherPt[possibleGatherPtNumber].y = midYPt1;
- possibleGatherPtNumber++;
- }
- }
- //獲取所有騎士相聚需要走的天數
- void getWalkDays()
- {
- for(int i = 0; i < possibleGatherPtNumber; i++)
- {
- KnightPt kpt = possibleGatherPt[i];
- for(int j = 0; j < knightNumber; j++)
- {
- //得到一個騎士要走多少天
- int oneKnightWalkDay = MAX(ABSOLUTE(kinghtPt[j].x - kpt.x), ABSOLUTE(kinghtPt[j].y - kpt.y));
- //騎士行走的最多天數,爲相聚的天數
- gatherDays[i] = MAX(gatherDays[i], oneKnightWalkDay);
- //獲取所有騎士相聚的天數
- walkDays[i] += oneKnightWalkDay;
- }
- }
- minGatherDays = gatherDays[0];
- minWalkDay = walkDays[0];
- for(int j = 0; j < possibleGatherPtNumber; j++)
- {
- if(gatherDays[j] < minGatherDays) minGatherDays = gatherDays[j];
- if(walkDays[j] < minWalkDay) minWalkDay = walkDays[j];
- }
- }
- int wmain(wchar_t *argv[], int argn)
- {
- cout << "input knight number. range(0 < n <= 64)" << endl;
- cin >> knightNumber;
- cout << "knight all position" << endl;
- for(int i = 0; i < knightNumber; i++)
- {
- cout << "input knight " << i+1 << " position range( 0 ~ 7)" << endl;
- cin >> kinghtPt[i].x;
- cin >> kinghtPt[i].y;
- }
- getPossibleGatherPoint();
- getWalkDays();
- for(int k = 0; k < possibleGatherPtNumber; k++)
- {
- if(minGatherDays == gatherDays[k] && minWalkDay == walkDays[k])
- {
- cout << "--------------------------" << endl;
- cout << minGatherDays << " days, all gather can gather" << endl;
- cout << "gather position is x = " << possibleGatherPt[k].x << " y = " << possibleGatherPt[k].y << endl;
- cout << "all knight walk day is " << minWalkDay << endl;
- cout << "--------------------------" << endl;
- }
- }
- system("pause");
- }
一年前的試題:
第一題------(30分)
請實現以下函數把一個用阿拉伯字符串表示的自然數(串長大於0,小於13,串保證是合法的)轉換成相應的中文字符串。例如1234567890,應輸出“十二億三千四百五十六萬七千八百九十” 。分析:這是一道很經典的題目。猶記得去年博主面有道實習的時候也被問到了這道題目。首先呢,這題用java處理起來還是會比C++在代碼上會簡潔一些。先看個java版本的吧,話說博主代碼能力很水,有問題歡迎大家留言指正,但求輕噴,謝謝。
- package com.test;
- public class NumberProcess {
- private static final String[] UNITS = { "", "十", "百", "千", "萬", "十", "百", "千", "億", "十", "百", "千", };
- private static final String[] NUMS = { "零", "一", "二", "三", "四", "五", "六", "七", "八", "九", };
- /**
- * 阿拉伯數字轉換成中文字符串
- * @param value 要轉換的數字
- * @return 返回數字轉後的中文字符串
- */
- public static String number2Chinese(int value) {
- String result = ""; //轉譯結果
- for (int i = String.valueOf(value).length() - 1; i >= 0; i--) {
- int r = (int) (value / Math.pow(10, i));//value / Math.pow(10, i) 截位匹配單位
- result += NUMS[r % 10] + UNITS[i];
- }
- result = result.replaceAll("零[十, 百, 千]", "零");//匹配字符串中的 "零[十, 百, 千]" 替換爲 "零"
- result = result.replaceAll("零+", "零");//匹配字符串中的1或多個 "零" 替換爲 "零"
- result = result.replaceAll("零([萬, 億])", "$1");
- result = result.replaceAll("億萬", "億"); //億萬位拼接時發生的特殊情況
- if (result.startsWith("一十")) { //判斷是否以 "一十" 開頭 如果是截取第一個字符
- result = result.substring(1);
- }
- if (result.endsWith("零")) { //判斷是否以 "零" 結尾 如果是截取除 "零" 外的字符
- result = result.substring(0, result.length() - 1);
- }
- return result;
- }
- public static void main(String[] args) {
- System.out.println(NumberProcess .number2Chinese(1234567890));
- }
- }
第二題------(30分)
求一個全英文字符串的不同組合數目,串的長度小於30。實例1“cat”有7種不同的組合:c、a、t、ca、ct、at、cat 示例2 “all”有5種不同的組合:a、l、al、ll、all
分析:就像之前找工作筆試面試那些事兒(15)---互聯網公司面試的零零種種和多家經驗中提到的,在做算法題的時候,遞歸和分治是時常要存於腦中的思路。這題如果考慮遞歸求解的話,考慮求長度爲n的字符串中m個字符的組合,設爲C(n,m)。原問題的解即爲所有的C(n, 1), C(n, 2),...C(n, n)。對於求C(n, m),從第一個字符開始掃描,每個字符有兩種情況,要麼被選中,要麼不被選中,如果被選中,遞歸求解C(n-1, m-1)。如果未被選中,遞歸求解C(n-1, m)。不管哪種方式,n的值都會減少,在n=0或m=0時遞歸結束。這題有個小問題是這裏的“不同”,博主的方法能輸出所有結果,但是是不是會有重複(求教)?
- //函數功能 : 在字符串中選m個字符
- //函數參數 : pStr爲字符串,m爲選的元素個數,result爲選中的字符
- //返回值 : 無
- void Combination_m(char *pStr, int m, vector<char> &result)
- {
- if(pStr == NULL || (*pStr == '\0'&& m != 0))
- return;
- if(m == 0) //遞歸終止條件
- {
- for(unsigned i = 0; i < result.size(); i++)
- cout<<result[i];
- cout<<endl;
- return;
- }
- //選擇這個元素
- result.push_back(*pStr);
- Combination_m(pStr + 1, m - 1, result);
- result.pop_back();
- //不選擇這個元素
- Combination_m(pStr + 1, m, result);
- }
- //函數功能 : 求一個字符串的組合
- //函數參數 : pStr爲字符串
- //返回值 : 無
- void Combination(char *pStr)
- {
- if(pStr == NULL || *pStr == '\0')
- return;
- int number = strlen(pStr);
- for(int i = 1; i <= number; i++)
- {
- vector<char> result;
- Combination_m(pStr, i, result);
- }
- }
第三題------(40分)
1.編寫函數對一顆二叉樹進行廣度遍歷——從上往下逐層、同一層從左至右遍歷。
2.同爲分層遍歷,但是先輸出最後一層,然後輸出倒數第二層,···,最後輸出第一層。
分析:1)第一小題是廣度優先搜索的一個示例,用一個隊列存儲節點的話,會發現,如果第k層節點一個都沒出隊,那麼隊列中必然沒有k+1層節點,而且如果第k層節點剛好都出隊了,隊列中只有第k+1層節點,且包含所有的k+1層節點。所以從第一層開始,把根節點入隊,記錄當前層節點數1,然後輸出這個層得所有節點,跟新隊列,然後正好隊列中就只有且包含所有第2層得節點數了,依次類推直到隊列爲空爲止。
2)第二小題可以在遍歷的過程中,記錄每層元素個數,注意遍歷中只入隊不出隊,每層遍歷是否結束,需要多設置一些計數變量。也可使用啞元素的方法,即在每層中間插入NULL,同樣,遍歷中也是隻入隊不出對,每層遍歷是否結束,需要多設置一些計數變量。
第一小題代碼如下:
- #include<iostream>
- #include<deque>
- using namespace std;
- struct NODE {
- NODE* pLeft;
- NODE* pRight;
- int value;
- };
- void PrintTreeByLevel(const NODE* root) {
- deque<const NODE*> store;
- int left_num;
- if(!root)
- return;
- store.push_back(root);
- while(!store.empty()) {
- left_num = store.size(); // 當前層的節點數
- while(left_num-- > 0) {
- const NODE* tmp = store.front();
- store.pop_front();
- cout << tmp->value << " ";
- if(tmp->pLeft)
- store.push_back(tmp->pLeft);
- if(tmp->pRight)
- store.push_back(tmp->pRight);
- }
- cout << endl;
- }
- }
- void ReversePrintTreeByLevel(const NODE* root) {
- deque<const NODE*> store;
- int index = 0; // 遍歷元素和啞元素的下標
- int no = 0; // 遍歷過的元素個數
- if(!root) {
- return;
- }
- store.push_back(root);
- index = 0;
- while(index < store.size()) {
- store.push_back(NULL); // 啞元素
- while(store[index] != NULL) { // 訪問當前層
- no++;
- if(store[index]->pRight)
- store.push_back(store[index]->pRight);
- if(store[index]->pLeft)
- store.push_back(store[index]->pLeft);
- index++;
- }
- index++;
- }
- for(int i=store.size()-1; i>=0; i--) {
- if(store[i] == NULL)
- cout << endl;
- else {
- cout << store[i]->value << " ";
- }
- }
- cout << endl;
- }
今年的題:
一、單選題
1、有變量int i = 0; int a = i++; int b=++a; int c = a+b; 請問表達式 a?b:c 的值是(B)
A、0 B、1 C、2 D、3
分析:基礎題,考察自加自減運算符和條件運算符。
2、32位環境下,int *p=new int[10];請問sizeof(p)的值爲(A)
A、4 B、10 C、40 D、8
分析:sizeof每年必考啊,這裏其實就是一個指針的大小。
3、有語句char str[] = "abcde";請問表達式sizeof(str)的值是(D)
A、1 B、4 C、5 D、6
分析:恩,和上一題對應起來了,這裏是串所佔空間。
4、有函數int func(int i)的實現爲()
int func(int i)
if(i > 1)
return i*func(i-1);
else
return 1;
請問函數調用f(5)的返回值是多少(D)
A、5 B、15 C、20 D、120
分析:階乘運算,還真有公司願意年年出-_-||
5、請問以下說法,哪個是正確的(C)
A、每個類都有一個無參數的構造函數
B、每個類都有一個拷貝構造函數
C、每個類能有多個構造函數
D、每個類能有多個析構函數
分析:顯然啊。。。不然怎麼用多種方式定義新對象
6、用class關鍵字定義的類,其成員默認的訪問屬性爲(A)
A、private B、protected C、public D、無定義
7、類的成員有三種訪問屬性,分別是public、protected、private,子類能夠訪問的成員是(B)
A、都能訪問
B、public和protected
C、public和private
D、protected和private
8、請問對一個排好序的數組進行查找,時間複雜度爲(B)
A、O(n) B、O(lgn) C、O(nlgn) D、O(1)
分析:咳咳!說明一下,堆排序真心是要注意的一種排序方式,出現頻度極高。建議還是拿本算法導論出來啃啃這一節吧,一次掌握,終生受用。一次堆調整或者在排好序的堆內查找都是O(lgn)
9、以下二叉樹:
甲
/ \
乙 戊
/ \ \
丙 丁 己
後序遍歷的結果是(C)
A、丙乙丁甲戊己 B、甲乙丙丁戊己 C、丙丁乙己戊甲 D、丙丁己乙戊甲
10、看以下代碼:
A *pa = new A[10];
delete pa;
則類A的構造函數和析構函數分別執行了幾次(D)
A、1 1 B、10 10 C、1 10 D、10 1
11、看以下代碼:
class A
{
public:
~A();
};
A::~A()
{
printf("delete A ");
}
class B : public A
{
public:
~B();
};
B::~B()
{
printf("delete B ");
}
請問執行以下代碼
A *pa = new B();
delete pa;
輸出的串是(A)
A、delete A B、delete B C、delete B delete A D、delete A delete B
12、文件長度是一個大於0的整數,用變量unsigned file_length來表示,把文件分成塊,每塊的長度也是一個大於0的整數,用變量unsigned block_length來表示,則文件被分成的塊數爲(D)
A、file_length/block_length B、file_length/block_length+1
C、(file_length+block_length-1)/block_length D、((file_length-1)/block_length+1
13、整數int i = 0xFE78DA45; int k = 0xAC3189B2;則i^k的值爲(A)
A、0x524953f7 B、0xAC308800 C、0xFE79DBF7 D、0X0000001
14、看以下代碼:
class parent
{
public:
virtual void output();
};
void parent::output()
{
printf("parent!");
}
class son : public parent
{
public:
virtual void output();
};
void son::output()
{
printf("son!");
}
則以下程序段:
son s;
::memset(&s , 0 , sizeof(s));
parent& p = s;
p.output();
執行結果是(D)
A、parent! B、son! C、son!parent! D、沒有輸出結果,程序運行出錯
15、函數的局部變量所需存儲空間,是在哪裏分配的(D)
A、進程的數據段 B、進程的棧上 C、進程的堆上 D、以上都可以
16、以下STL的容器存放的數據,哪個肯定是排好序的(D)
A、vector B、deque C、list D、map
17、int a[][3]={{1},{3,2},{6,7,8},{9}};中a[2][1]的值是(D)
A、3 B、6 C、2 D、7
18、以下關於頭文件,說法正確的是(C)
A、#include<filename.h>,編譯器尋找頭文件時,會從當前編譯的源文件所在的目錄去找
B、#include“filename.h”,編譯器尋找頭文件時,會從通過編譯選項指定的目錄去找
C、多個源文件同時用到的全局整數變量,它的聲明和定義都放在頭文件中,是好的編程習慣
D、在大型項目開發中,把所有自定義的數據類型、全局變量、函數聲明都放在一個頭文件中,各個源文件都只需要包含這個頭文件即可,省去了要寫很多#include語句的麻煩,是好的編程習慣。
19、某棵完全二叉樹上有699個節點,則該二叉樹的葉子節點數爲(B)
A、349 B、350 C、188 D、187
20、在一個指向字符串的指針char *p_str,要把字符串中第4個字符的值改爲'a',正確的做法是(A)
A、p_str[3]='a' B、*(p_tr+3)='a' C、p_str[4]='a' D、*(p_tr+4)='a'
二、多選題
1、已知一段文本有1382個字符,使用了1382個字節進行存儲,這段文本全部是由a、b、c、d、e這5個字符組成,a出現了354次,b出現了483次,c出現了227次,d出現了96次,e出現了232次,對這5個字符使用哈夫曼(Huffman)算法進行編碼,則以下哪些說法正確(ACD)
A、使用哈夫曼算法編碼後,用編碼值來存儲這段文本將花費最少的存儲空間
B、使用哈夫曼算法進行編碼,a、b、c、d、e這5個字符對應的編碼值是唯一確定的
C、使用哈夫曼算法進行編碼,a、b、c、d、e這5個字符對應的編碼值可以有多套,但每個字符編碼的位(bit)數是確定的
D、b這個字符的哈夫曼編碼值位數應該最短,d這個字符的哈夫曼編碼值位數應該最長
2、下列表達式中,不合法的是(AD)
已知:double d = 3.2; int n = 3;
A、d<<2;
B、d/n
C、!d && (n-3)
D、(d-0.2)|n
3、下面描述正確的是(BC)
A、while循環語句的循環體至少執行1次
B、do-while循環可以寫成while循環的格式
C、continue語句可以出現在各種循環體中
D、break語句不可以出現在循環體內
4、關於內聯函數正確的是(B)
A、類的私有成員函數不能作爲內聯函數
B、在所有類說明中內部定義的成員函數都是內聯函數
C、類的保護成員函數不能作爲內聯函數
D、使用內聯函數的地方會在運行階段用內聯函數體替換掉
5、下面模板聲明中,哪些是非法的(BD)
A、template<class Type>class C1;
B、template<class T,U , class V>class C2;
C、template<class C1 , typename C2>class C3{};
D、template<typename myT , class myT>class C4{};
6、在使用瀏覽器打開一個網頁的過程中,瀏覽器會使用的網絡協議包括(ABC)
A、DNS B、TCP C、HTTP D、Telnet
7、下面屬於構造散列函數的方法是(ABCD)
A、直接定址法
B、數字分析法
C、乘餘取整法
D、平方取中法
8、拷貝構造函數的特點是(BD)
A、該函數名同類名,也是一種構造函數,該函數返回自身引用
B、該函數只有一個參數,必須是對某個對象的引用
C、每個類都必須有一個拷貝初始化構造函數,如果類中沒有說明拷貝構造函數,則編譯器系統會自動生成一個缺省拷貝構造函數,作爲該類的保護成員
D、拷貝初始化構造函數的作用是將一個已知對象的數據成員值拷貝給正在創建的另一個同類的對象
9、下列關於虛函數的說法正確的是(BCD)
A、在構造函數中調用類自己的虛函數,虛函數的動態綁定機制還會生效。
B、在析構函數中調用類自己的虛函數,虛函數的動態綁定機制還會生效。
C、靜態函數不可以是虛函數
D、虛函數可以聲明爲inline
10、下列對函數double add(int a , int b)進行重載,正確的是(ABC)
A、int add(int a ,int b ,int c)
B、int add(double a , double b)
C、double add(double a , double b)
D、int add(int a , int b)
筆試題歸類總結
題目如上,分析還未完全做完,下次接着寫,先總體分析一下考點吧,並順帶對應一下它們在我之前做的知識總結中的位置(沒有的部分說明之前的總結還有一定的疏忽,後期會補上):
1) 二維數組
2) 指針和二維指針
3) 二叉樹的三種遍歷方式
4) 棧和隊列的特性/進出棧序列
5) 運算符執行優先級 ----找工作筆試面試那些事兒(1)---C,C++基礎和編程風格(2)
6) 內聯函數 ----找工作筆試面試那些事兒(4)---C++函數高級特徵
7) 構造函數和析構函數 ----找工作筆試面試那些事兒(5)---構造函數、析構函數和賦值函數
8) 運算符重載 ----找工作筆試面試那些事兒(4)---C++函數高級特徵
9) 多態
10)函數重載 ----找工作筆試面試那些事兒(4)---C++函數高級特徵
11)宏的邊際效應 ----找工作筆試面試那些事兒(1)---C,C++基礎和編程風格(2)
12)sizeof ----找工作筆試面試那些事兒(3)---內存管理那些事
13)內存分配相關 ----找工作筆試面試那些事兒(3)---內存管理那些事
14)內存對齊 ----找工作筆試面試補充知識(1)---內存對齊
15)形參和實參
16)結構體和內存
17)程序題裏面的遞歸
18)哈夫曼編碼
19)模板
20)網絡協議
21)hash相關