Google面試筆試題

才智咖 人氣:1.48W

谷歌筆試題:將無向無環連通圖轉換成深度最小的樹

Google面試筆試題

已知一個無向無環連通圖T的所有頂點和邊的資訊,現需要將其轉換為一棵樹,要求樹的深度最小,請設計一個演算法找到所有滿足要求的樹的根結點,並分析時空複雜度。

最簡單直接的方法就是把每個節點都試一遍:

假設某個節點為根節點,計算樹的深度。當遍歷完所有節點後,也就找到了使樹的深度最小的根節點。

但這個方法的複雜度很高。如果有n個節點,則時間複雜度為O(n^2)。

樹的深度取決於根節點到最深葉節點的距離,所以我們可以從葉節點入手。

葉節點會且只會和某一個節點連通(反之不成立,因為根節點也可能只和一個節點連通),所以我們很容易找到所有可能的葉節點。

題目可以等價於找到了兩個葉節點,使得兩個葉節點之間的距離最遠。根節點就是這兩個葉節點路徑的中間點(或者中間兩個點的任意一個)。

我們可以每次都將連線度為1的節點刪掉,直到最後只剩下1個或2個節點,則這一個節點,或者兩個節點中的任意一個,就是我們要找的根節點。

 谷歌筆試題:將字串中的小寫字母排在大寫字母的前面

有一個由大小寫組成的字串,現在需要對它進行修改,將其中的所有小寫字母排在大寫字母的前面(大寫或小寫字母之間不要求保持原來次序)。

初始化兩個int變數A和B,代表字串中的兩個位置。開始時A指向字串的第一個字元,B指向字串的最後一個字元。

逐漸增加A的值使其指向一個大寫字母,逐漸減小B使其指向一個小寫字母,交換A,B所指向的字元,然後繼續增加A,減小B....。

當A>=B時,就完成了重新排序。

i指向最後一個小寫字元,j尋找小寫字元。

void swapString(char* str, int len) { int i=-1; int j=0; for(j=0; j<len; str[j]="" &&="" if(str[j]<="z">='a') { i++; swap(str[i], str[j]); } } }

谷歌筆試題:在重男輕女的國家裡,男女的比例是多少?

在一個重男輕女的國家裡,每個家庭都想生男孩,如果他們生的孩子是女孩,就再生一個,直到生下的是男孩為止。這樣的國家,男女比例會是多少?

還是1:1。

在所有出生的第一個小孩中,男女比例是1:1;在所有出生的第二個小孩中,男女比例是1:1;.... 在所有出生的第n個小孩中,男女比例還是1:1。

所以總的男女比例是1:1。

谷歌筆試題:如何拷貝特殊連結串列

有一個特殊的連結串列,其中每個節點不但有指向下一個節點的指標pNext,還有一個指向連結串列中任意節點的指標pRand,如何拷貝這個特殊連結串列?

拷貝pNext指標非常容易,所以題目的難點是如何拷貝pRand指標。

假設原來連結串列為A1 -> A2 ->... -> An,新拷貝連結串列是B1 -> B2 ->...-> Bn。

為了能夠快速的找到pRand指向的節點,並把對應的關係拷貝到B中。我們可以將兩個連結串列合併

A1 -> B1 -> A2 -> B2 -> ... -> An -> Bn。

從A1節點出發,很容易找到A1的pRand指向的節點Ax,然後也就找到了Bx,將B1的pRand指向Bx也就完成了B1節點pRand的拷貝。依次類推。

當所有節點的pRand都拷貝完成後,再將合併連結串列分成兩個連結串列就可以了。

class ListNode { int value; ListNode* p_next; ListNOde* p_rand; public ListNode(int v, ListNode* next, ListNode* rand): value(v), p_next(next), p_rand(rand) { } }; ListNode*copyList(ListNode*p) { if(p!=null) { /*構建交叉陣列 p0->q0->p1->q1->p2->q2...*/ ListNOde*ppre=p; ListNode*post=->next; while(pre!=null) { pre->next=newListNode(pre->value,post,pre->p_rand->p_next); pre=last; lastlast=last->p_next; } /*拆分成被拷貝陣列和拷貝陣列 p0->p1->p2....;q0->q1->q2....*/ ppre=p; ListNode*res=p->p_next; while(res->p_next!=null) { p->p_next=res->p_next; res->p_next=res->p_next->p_next; } returnres; }else { returnp; } }

如果在高速公路上30分鐘內看到一輛車開過的機率是0.95,那麼在10分鐘內看到一輛車開過的機率是多少?(假設為常概率條件下)

假設10分鐘內看到一輛車開過的概率是x,那麼沒有看到車開過的概率就是1-x,30分鐘沒有看到車開過的概率是(1-x)^3,也就是0.05。所以得到方程(1-x)^3 = 0.05

解方程得到x大約是0.63。

 谷歌筆試題:從25匹馬中找出最快的3匹

最少需要7次。

首先將馬分成a,b,c,d,e 5個組,每組5匹,每組單獨比賽。然後將每組的第一名放在一起比賽。假設結果如下

a0,a1,a2,a3,a4

b0,b1,b2,b3,b4

c0,c1,c2,c3,c4

d0,d1,d2,d3,d4

e0,e1,e2,e3,e4

其中a, b,c,d,e小組都是按照名次排列(速度a0>a1>a2>a3>a4, b0>b1....)。並第6次比賽的結果為a0>b0>c0>d0>e0。

那麼第6次比賽結束後,我們知道最快的一匹為a0。

我們知道第2名的馬一定是a1或者b0,所以在接下來的比賽中要包含這兩匹馬。如果a1快,那麼第3名是a2或者b0,如果b0快,那麼第3名是a1,b1或者c0。也就是說第2名和第3名一定在a1,a2,b0,b1和c0當中,所以在第7場比賽中包括這5匹馬就可以得到第2名和第3名。

所以7次比賽就可以獲得前3名的馬。

 谷歌筆試題:將無向無環連通圖轉換成深度最小的樹

已知一個無向無環連通圖T的所有頂點和邊的資訊,現需要將其轉換為一棵樹,要求樹的深度最小,請設計一個演算法找到所有滿足要求的樹的根結點,並分析時空複雜度。

最簡單直接的方法就是把每個節點都試一遍:

假設某個節點為根節點,計算樹的深度。當遍歷完所有節點後,也就找到了使樹的深度最小的根節點。

但這個方法的複雜度很高。如果有n個節點,則時間複雜度為O(n^2)。

樹的深度取決於根節點到最深葉節點的距離,所以我們可以從葉節點入手。

葉節點會且只會和某一個節點連通(反之不成立,因為根節點也可能只和一個節點連通),所以我們很容易找到所有可能的葉節點。

題目可以等價於找到了兩個葉節點,使得兩個葉節點之間的距離最遠。根節點就是這兩個葉節點路徑的中間點(或者中間兩個點的任意一個)。

我們可以每次都將連線度為1的節點刪掉,直到最後只剩下1個或2個節點,則這一個節點,或者兩個節點中的任意一個,就是我們要找的根節點。

谷歌筆試題:將字串中的小寫字母排在大寫字母的前面

有一個由大小寫組成的字串,現在需要對它進行修改,將其中的所有小寫字母排在大寫字母的前面(大寫或小寫字母之間不要求保持原來次序)。

初始化兩個int變數A和B,代表字串中的兩個位置。開始時A指向字串的第一個字元,B指向字串的最後一個字元。

逐漸增加A的值使其指向一個大寫字母,逐漸減小B使其指向一個小寫字母,交換A,B所指向的字元,然後繼續增加A,減小B....。

當A>=B時,就完成了重新排序。

i指向最後一個小寫字元,j尋找小寫字元。

void swapString(char* str, int len) { int i=-1; int j=0; for(j=0; j<len; str[j]="" &&="" if(str[j]<="z">='a') { i++; swap(str[i], str[j]); } } }

谷歌筆試題:在重男輕女的`國家裡,男女的比例是多少?

在一個重男輕女的國家裡,每個家庭都想生男孩,如果他們生的孩子是女孩,就再生一個,直到生下的是男孩為止。這樣的國家,男女比例會是多少?

還是1:1。

在所有出生的第一個小孩中,男女比例是1:1;在所有出生的第二個小孩中,男女比例是1:1;.... 在所有出生的第n個小孩中,男女比例還是1:1。

所以總的男女比例是1:1。

谷歌筆試題:如何拷貝特殊連結串列

有一個特殊的連結串列,其中每個節點不但有指向下一個節點的指標pNext,還有一個指向連結串列中任意節點的指標pRand,如何拷貝這個特殊連結串列?

拷貝pNext指標非常容易,所以題目的難點是如何拷貝pRand指標。

假設原來連結串列為A1 -> A2 ->... -> An,新拷貝連結串列是B1 -> B2 ->...-> Bn。

為了能夠快速的找到pRand指向的節點,並把對應的關係拷貝到B中。我們可以將兩個連結串列合併成

A1 -> B1 -> A2 -> B2 -> ... -> An -> Bn。

從A1節點出發,很容易找到A1的pRand指向的節點Ax,然後也就找到了Bx,將B1的pRand指向Bx也就完成了B1節點pRand的拷貝。依次類推。

當所有節點的pRand都拷貝完成後,再將合併連結串列分成兩個連結串列就可以了。

class ListNode { int value; ListNode* p_next; ListNOde* p_rand; public ListNode(int v, ListNode* next, ListNode* rand): value(v), p_next(next), p_rand(rand) { } }; ListNode*copyList(ListNode*p) { if(p!=null) { /*構建交叉陣列 p0->q0->p1->q1->p2->q2...*/ ListNOde*ppre=p; ListNode*post=->next; while(pre!=null) { pre->next=newListNode(pre->value,post,pre->p_rand->p_next); pre=last; lastlast=last->p_next; } /*拆分成被拷貝陣列和拷貝陣列 p0->p1->p2....;q0->q1->q2....*/ ppre=p; ListNode*res=p->p_next; while(res->p_next!=null) { p->p_next=res->p_next; res->p_next=res->p_next->p_next; } returnres; }else { returnp; } }

如果在高速公路上30分鐘內看到一輛車開過的機率是0.95,那麼在10分鐘內看到一輛車開過的機率是多少?(假設為常概率條件下)

假設10分鐘內看到一輛車開過的概率是x,那麼沒有看到車開過的概率就是1-x,30分鐘沒有看到車開過的概率是(1-x)^3,也就是0.05。所以得到方程(1-x)^3 = 0.05

解方程得到x大約是0.63。

谷歌筆試題:從25匹馬中找出最快的3匹

最少需要7次。

首先將馬分成a,b,c,d,e 5個組,每組5匹,每組單獨比賽。然後將每組的第一名放在一起比賽。假設結果如下

a0,a1,a2,a3,a4

b0,b1,b2,b3,b4

c0,c1,c2,c3,c4

d0,d1,d2,d3,d4

e0,e1,e2,e3,e4

其中a, b,c,d,e小組都是按照名次排列(速度a0>a1>a2>a3>a4, b0>b1....)。並第6次比賽的結果為a0>b0>c0>d0>e0。

那麼第6次比賽結束後,我們知道最快的一匹為a0。

我們知道第2名的馬一定是a1或者b0,所以在接下來的比賽中要包含這兩匹馬。如果a1快,那麼第3名是a2或者b0,如果b0快,那麼第3名是a1,b1或者c0。也就是說第2名和第3名一定在a1,a2,b0,b1和c0當中,所以在第7場比賽中包括這5匹馬就可以得到第2名和第3名。

所以7次比賽就可以獲得前3名的馬。