作者:寒小陽
時間:2013年9月。
出處:http://blog.csdn.net/han_xiaoyang/article/details/11924701
宣告:版權所有,轉載請註明出處,謝謝。

題目是網上找的,答案博主自己做的,有不當之處或者有更好的方法歡迎留言!

第一題

一堆硬幣,一個機器人,如果是反的就翻正,如果是正的就拋擲一次,無窮多次後,求正反的比例(哈爾濱站)

典型的數學概率題(好吧,說明數學還是很重要滴,大家去筆試面前還是鞏固一下概率比較好,恩),這裡假設無窮多次後正面朝上的比例為x,則反面朝上的比例為1-x;則再投遞一次,根據題意,正面朝上的概率的就變成1-x+(1/2*x),,反面朝上的概率變為1/2*x.因為此時已經達到平衡的狀態,則該次投遞前後概率應該不變,即1-x=1/2*x。解得x2/3


第二題

k連結串列翻轉。給出一個連結串列和一個數k,比如連結串列123456k=2,則翻轉後214365,若k=3,翻轉後321654,若k=4,翻轉後432156,用程式實現

  1. /*************************************************************************************************

  2. /*首先,博主說明一下,博主不清楚k>連結串列長度的時候,題目的本意是讓我們怎麼處理的,博主這裡直接沒有做任何翻轉,將原連結串列返回了。

  3. **************************************************************************************************/

  4. #include<stdio.h>

  5. #include<stdlib.h>

  6. #include<iostream>

  7. usingnamespace std;

  8. //定義連結串列節點

  9. struct Node{

  10. int data;

  11. Node *next;

  12. };

  13. //函式在給定頭結點和尾節點的情況下,對整個連結串列做翻轉

  14. void ReverseLinkList(Node *head,Node *end){

  15. if(head==NULL||end==NULL) return;

  16. Node *pre=NULL,*cur=head,*stop=end->next;

  17. while(cur!=stop){

  18. Node* nxt=cur->next;

  19. cur->next=pre;

  20. pre=cur;

  21. cur=nxt;

  22. }

  23. }

  24. //k連結串列翻轉

  25. Node* ReverseKLinkList(Node *head,int k){

  26. if(head==NULL||k<=0) return NULL;

  27. Node *cur=head;

  28. for(int i=0;i<k-1;i++){

  29. cur=cur->next;

  30. if(cur==NULL)

  31. break;

  32. }

  33. //在連結串列長度小於k的情形下,直接返回原連結串列

  34. if(cur==NULL) return head;

  35. Node* begin=cur->next,*end=begin;

  36. Node* pre=head;

  37. ReverseLinkList(head,cur);

  38. while(begin!=NULL){

  39. for(int i=0;i<k-1;i++){

  40. end=end->next;

  41. if(end==NULL)

  42. break;

  43. }

  44. if(end==NULL){

  45. pre->next=begin;

  46. break;

  47. }

  48. else{

  49. Node *nextbegin=end->next;

  50. ReverseLinkList(begin,end);

  51. pre->next=end;

  52. pre=begin;

  53. begin=end=nextbegin;

  54. }

  55. }

  56. return cur;

  57. }

  58. int main(){

  59. int a[]={0,,1,2,3,4,5,6,7,8,9,10,11};

  60. Node* node[12];

  61. for(int i=0;i<12;i++){

  62. node[i]=new Node;

  63. node[i]->next=NULL;

  64. node[i]->data=a[i];

  65. }

  66. for(int i=0;i<11;i++){

  67. node[i]->next=node[i+1];

  68. }

  69. Node *tmp=ReverseKLinkList(node[0],4);

  70. for(;tmp!=NULL;tmp=tmp->next){

  71. cout<<tmp->data<<endl;

  72. }

  73. system(“pause”);

  74. return 0;

  75. }

第三題

ABCD死人要在夜裡過一座橋,他們通過這座橋分別需要耗時1,2,5,10分鐘,現在只有一隻手電,過橋時必須要帶著手電,並且同時最多隻能兩個人一起過橋。請問如何安排能夠讓四個人儘快都過橋。(長沙站)

如果博主沒有記錯的話,這是騰訊幾年前考過的一道題,一到校招時,就發現各大公司筆試題抄來抄去,好吧,停止吐槽。這種智力題一向是博主這樣智力平庸人的硬傷,恩,直接上答案了。

第一步:A(1)B(2)過橋,A(1)返回Cost1+2s

第二步:C(5)D(10)過橋,B(2)返回Cost10+2s

第三步:A(1)B(2)過橋Cost2 s

總共耗時3+12+2=17s


第四題

有25匹馬,每匹馬都以恆定的速度賽跑,當然馬與馬之間的速度是不相等的,總共有5個賽道,就是說每輪最多隻能有5個馬同時賽跑。問題是:要確定出跑的最快的前三名馬,需要最少多少輪比賽?(長沙站)

不多說了,直接上答案吧。

總共需要7
1)首先分5組 比賽5
(ABCDE)決出
A1 A2 A3 A4 A5
B1 B2 B3 B4 B5
C1 C2 C3 C4 C5
D1 D2 D3 D4 D5
E1 E2 E3 E4 E5
2再比賽1
A1 B1 C1 D1 E1比賽
至少可以淘汰2
假設 A1 > B1 > C1 > D1E1
則 最快的必然是 A1 A2 A3 B1 B2 C1中的3
A1已經確定有
3則最後一場對A2 A3 B1 B2 C1進行比較,選出前2


第五題

在有團購之前,大家都是現場買門票的,公園的門票是5元;某天售票處開門時沒有準備零錢。假設一天來購票的一次有2N個人,其中有N個人有5元零錢,其它N個人只有10元面值的錢;假設每人只買一張票。請問任何人都不必為找零而等待的概率是多少?(長沙站)

這道題,好吧,博主的第一反應是:這是標準的Catalan數的應用吧!(好吧,打算隨後拿一篇出來介紹下Catalan),博主奇怪的是,美團今年的校招題,腫麼數學題這麼多-_-||

隱隱約約記得這道題貌似《程式設計之美》上也有,為了將問題簡單化,將持有5元的人看成1,持有10元的人看成0,這樣,只要滿足:在任何0位置之前,1的數目多於0的數目,就能滿足要求,則該題求解的為滿足要求的排列佔全部排列的比例。

1)求2n10的全排列數目:C(2n,n),即從2n個位置中選取n放置0(或者1)。

2)求取不滿足要求的組合數(合法的組合數不好求):

不滿足要求的組合數的特點:總能找到一個位置K,使得0的數目比1的數目多1。那麼很明顯,k後面的0的數目比1的數目要少1.(為什麼要找位置k?因為,我要讓前面K個位置01排列不管怎麼排列都不合法)

此後,我們關注k位置後面的排列:因為k後面的排列中,明顯01少,那麼我們可以將01互換(為什麼要互換?首先,01互換後,兩種排列方式的總數目是不變的,其次,互換後的排列中011個,那麼不管怎麼排列,都不合法),這樣互換後2n個數的排列不管怎麼排列都不合法(值得注意的是,互換後的組合排列數目,和互換前的是相同的,因為前面的排列不變且後面排列組合方式的數目一樣。

現在來計算互換後排列的數目:互換後排列的數目中0n+1個,1n-1個,那麼組合數就相當於從2n個位置選取n+1個位置放0,即為C2n,n+1

所求結果為( C(2n,n)-C(2n,n+1) )/ C(2n,n)


第六題

有一個函式“int f(int n)”,請編寫一段程式測試函式f(n)是否總是返回0,並新增必要的註釋和說明。

這一題博主木有明確的思路,感覺上黑盒測試的話只能從INT_MININT_MAX全部測試了,或者加上隨機演算法,抽樣檢測。大家有好的方法歡迎留言。

第七題

用你熟悉的語言編寫程式用兩個棧(Stack)模擬佇列(Queue)的先進先出操作,僅實現addremove方法即可。(長沙站)

非常非常經典的一道老題了,假設兩個棧s1和s2,且都為空。可以認為棧s1提供入佇列的功能,棧s2提供出佇列的功能。

1入佇列:入棧s1。

2出佇列:如果棧s2不為空,直接彈出棧s2的資料;如果棧s2為空,則依次彈出棧s1的資料,放入棧s2中,再彈出棧s2的資料。

  1. #include <iostream>

  2. #include <stack>

  3. usingnamespace std;

  4. template<class T>

  5. struct MyQueue

  6. {

  7. void add(T &t)

  8. {

  9. s1.push(t);

  10. }

  11. T front()

  12. {

  13. if(s2.empty())

  14. {

  15. if(s1.size() == 0) throw;

  16. while(!s1.empty())

  17. {

  18. s2.push(s1.top());

  19. s1.pop();

  20. }

  21. }

  22. return s2.top();

  23. }

  24. void remove()

  25. {

  26. if(s2.empty())

  27. {

  28. while(!s1.empty())

  29. {

  30. s2.push(s1.top());

  31. s1.pop();

  32. }

  33. }

  34. if(!s2.empty())

  35. s2.pop();

  36. }

  37. stack<T> s1;

  38. stack<T> s2;

  39. };

  40. int main()

  41. {

  42. MyQueue<int> mq;

  43. for(int i=0; i< 10; ++i)

  44. {

  45. mq.add(i);

  46. }

  47. for(i=0; i< 10; ++i)

  48. {

  49. cout<<mq.front()<<endl;

  50. mq.remove();

  51. }

  52. return 0;

  53. }


第八題

編寫函式,獲取兩段字串的最長公共子串的長度,例如:

S1 = GCCCTAGCCAGDE

S2 = GCGCCAGTGDE

這兩個序列的最長公共字串為GCCAG,也就是說返回值為5.(長沙站)

說實話,一直以來見著的都是讓求最長公共子序列,突然讓求最長公共字串,反倒有些不習慣了,總覺得考最長公共子序列更合理一點吧,好吧,又看了一遍題,確實是求最長公共子串的長度。

為了說清楚一點,就用上面的例子吧,我們來列一張表,如下:

G C C C T A G C C A G D E

G 1 0 0 0 0 0 1 0 0 0 1 0 0

C 0 1 1 1 0 0 0 1 1 0 0 0 0

G1 0 0 0 0 0 1 0 0 0 1 0 0

C 0 1 1 1 0 0 0 1 1 0 0 0 0

C 0 1 1 1 0 0 0 1 1 0 0 0 0

A 0 0 0 0 0 1 0 0 0 1 0 0 0

G1 0 0 0 0 0 1 0 0 0 1 0 0

T 0 0 0 0 1 0 0 0 0 0 0 0 0

G1 0 0 0 0 0 1 0 0 0 1 0 0

D 0 0 0 0 0 0 0 0 0 0 0 1 0

E 0 0 0 0 0 0 0 0 0 0 0 0 1

則最長公共子串GCCAG為上圖中標出的最長斜對角線

博主在下面先寫一種最容易看懂的方法,這種方法的空間複雜度還可以再優化,不過這個問題,之後等博主寫到最長公共子序列、最長公共字串和最長遞增子序列專題的時候再寫吧。

  1. #include<stdio.h>

  2. #include<string.h>

  3. #define N 100

  4. //LCS問題:即求兩個字串最長公共子串的問題,這裡返回了公共字串,如果只求最長公共字串長度的話,之後有個簡單的程式,其實就是裡面的一部分

  5. char *LCS(char *a,char *b)

  6. {

  7. int len_a = strlen(a); //獲取字串的長度

  8. int len_b = strlen(b);

  9. char *p;

  10. int c[N][N] = {0}; //矩陣c記錄兩串的匹配情況

  11. int start,end,len,i,j; //start表明最長公共子串的起始點,end表明最長公共子串的終止點

  12. end = len = 0; //len表明最長公共子串的長度

  13. for(i=0;i<len_a;i++) //串開始從前向後比較

  14. {

  15. for(j=0;j<len_b;j++)

  16. {

  17. if(a[i] == b[j])

  18. if(i == 0 || j == 0)

  19. c[i][j] = 1;

  20. else

  21. c[i][j] = c[i-1][j-1] + 1;

  22. if(c[i][j] > len)

  23. {

  24. len = c[i][j];

  25. end = j;

  26. }

  27. }

  28. }

  29. start = end – len + 1;

  30. p = (char *)malloc(len+1); //陣列p記錄最長公共子串

  31. for(i=start;i<=end;i++)

  32. p[i-start] = b[i];

  33. p[len] = ` `;

  34. for(j=0;j<len_b;j++)

  35. {

  36. for(i=0;i<len_a;i++)

  37. printf(“%2d”,c[i][j]);

  38. printf(
    );

  39. }

  40. return p;

  41. }

  42. int main(int argc,char *argv[])

  43. {

  44. char str1[N],str2[N];

  45. printf(“請輸入字串1:”);

  46. gets(str1);

  47. printf(“請輸入字串2:”);

  48. gets(str2);

  49. printf(“最長子串為:%s
    ,LCS(str1,str2));

  50. return 0;

  51. }

  1. //只求最長公共字串長度

  2. int LCS(char *a,char *b)

  3. {

  4. int len_a = strlen(a); //獲取字串的長度

  5. int len_b = strlen(b);

  6. char *p;

  7. int c[N][N] = {0}; //矩陣c記錄兩串的匹配情況

  8. int start,end,len,i,j; //start表明最長公共子串的起始點,end表明最長公共子串的終止點

  9. end = len = 0; //len表明最長公共子串的長度

  10. for(i=0;i<len_a;i++) //串開始從前向後比較

  11. {

  12. for(j=0;j<len_b;j++)

  13. {

  14. if(a[i] == b[j])

  15. if(i == 0 || j == 0)

  16. c[i][j] = 1;

  17. else

  18. c[i][j] = c[i-1][j-1] + 1;

  19. if(c[i][j] > len)

  20. {

  21. len = c[i][j];

  22. end = j;

  23. }

  24. }

  25. }

  26. return len;

  27. }


第九題

100盞燈,從1~100編上號,開始時所有的燈都是關著的。
第一次,把所有編號是1的倍數的燈的開關狀態改變一次;
第二次,把所有編號是2的倍數的燈的開關狀態改變一次;
第三次,把所有編號是3的倍數的燈的開關狀態改變一次;
以此類推,直到把所有編號是100的倍數的燈的開關狀態改變一次。
問,此時所有開著的燈的編號。(哈爾濱站)

由於最開始燈是滅的,那麼只有經過奇數次改變開關狀態的燈是亮的。根據題意可知一個數字有多少約數就要開關多少次,所以最後亮著的燈的數學解釋就是:燈的編號有奇數個不同的約數。
一個數的約數按出現的奇偶個數分為以下兩種:
q 約數是成對出現的,比如8的約數對為:(18)、(24)。
q 約數是單個出現的,比如36的約數對為:(136)、(218)、(312)、(49)、(6)。
可以看出6自己單獨是36的約數,而不是和別的數連在一起。所以只有平方數才會有奇數個整型約數,才滿足本題的要求。從1100的平方數為:
149162536496481100
所以只有這些燈是亮的。