多益網路筆試題
一、有20張上下表面光滑的撲克牌,其中有8張向上,要求你閉著眼睛且不借助任何工具把這20張撲克牌分成兩堆,使得每堆向上的撲克牌的數目一樣多
答案:首先,把撲克牌隨機分成兩堆,一堆12張,一堆8張,假設12張的裡面有X張朝上的,那麼8張的裡面就有8-X張朝上的,X張朝下的,此時,把8張撲克牌全部反面,那麼朝上的也變成了X張。
二、有一串瑪瑙項鍊,項鍊上面有N個瑪瑙珠子,這些瑪瑙有M (M < = 9) 種不同的顏色,購買的時候可以只選擇購買項鍊長度為K(K<=n)的一段。現在有個苦逼的找不到工作的程式設計師想花最少的錢買到顏色最多的一段項鍊。要求時間複雜度O(N),空間複雜度O(1)。
答案:看到這道題,第一時間想不到O(N)的思路不要慌,先來看看最裸的思路應該怎麼寫?列舉每一個買項鍊的位置,然後模擬一遍統計有多少個不同的珠子,程式碼是這樣的:
<span style="font-size:14px;">for (int i=0;i<n;i++) nek[i+n]=nek[i]; //首先把項鍊的長度擴大一倍,這樣就把環拆成了一個鏈 for (int i=0;i<n;i++) //列舉每一個開頭 { int vis[10]; //vis是用來統計每一個顏色的珠子出現的次數 memset(vis,0,sizeof(vis)); for (int j=i;j<i+k;j++) { vis[arr[j]]++; } int num=0; for (int j=1;j<=9;j++) if (vis[j]>0) num++; ans=max(ans,num); }</span>
現在這樣做,複雜度是O(N*K)的,當K等於N的時候,複雜度就退化成了O(N*N)。所以要考慮如何降低一維複雜度,題目要求複雜度是O(N),因此,裡面的K這個複雜度是有可能被降下來的。來考慮下面一個例子:
1 1 2 3 4
假設K=4,那麼[1,4]這個區間裡面,vis陣列的值是:2 1 1 0,而[2,5]這個區間裡面,vis陣列的值是[1,1,1,1],這個是怎麼得到的呢?在[1,4]的vis的基礎上,vis[1]--,vis[4]++,只進行了兩次操作,就可以得到[2,5]區間的vis情況。所以,我們可以在一開始加入K個珠子進來,然後,每次,把最先進來的那個珠子X踢出去,此時vis[x]--,然後,再把下一個珠子Y加進來,此時vis[y]++,僅僅兩次操作,就可以得到下一個位置的值了。程式碼寫起來也更方便:
<span style="font-size:14px;">for (int i=0;i<n;i++) nek[i+n]=nek[i]; //首先把項鍊的長度擴大一倍,這樣就把環拆成了一個鏈
int vis[10]; //vis是用來統計每一個顏色的珠子出現的次數
memset(vis,0,sizeof(vis));
int num=0;
for (int i=0;i<k-1;i++) //首先把前k-1個珠子加進來
{
vis[arr[i]]++;
if (vis[arr[i]]==1) //如果這個珠子是第一次出現,num++
num++;
}
for (int i=k-1;i<n+k;i++) //列舉將每一個珠子i加進來
{
//首先加入第i顆珠子
vis[arr[i]]++;
if (vis[arr[i]]==1)
num++;
ans=max(ans,num);
//然後把當前第一顆珠子刪掉
vis[arr[i-(k-1)]]--;
if (vis[arr[i-(k-1)]]==0) //如果這顆珠子是自己顏色下唯一的那一顆
num--;
}</span>
如此一來,時間複雜度從O(N*K)降低到了O(N),空間複雜度是O(10)=O(1)
三、輸入一個整型陣列,數組裡有正數也有負數。
陣列中連續的一個或多個整陣列成一個子陣列,每個子陣列都有一個和。
求所有子陣列的和的最大值。要求時間複雜度為O(n)。
答案:典型的最大子段和問題,是動態規劃or貪心的入門題目。在這裡給一種貪心的做法:
從左到右不停的加,一旦當前的和小於0,就把之前的所有元素都拋棄掉。程式碼非常簡單:
<span style="font-size:14px;">int sum=0;
for (int i=0;i<n;i++)
{
if (sum<0) sum=0;
sum+=arr[i];
ans=max(ans,sum);
}</span>
四、假設:生男生女的概率都是50% (實際情況是生男的概率稍大一些,暫不考慮)
如果:政策允許生下一個孩子,如果是男孩就不能再生,發現是女孩,可以還繼續
生,直到生下來一個男孩不準再生了。
那麼:以後的生男生女的比例會偏離50%嗎?偏向哪邊?偏多少?說明理由
答案:做這種題目,千萬不要被題面所迷惑,要堅信男女比例是不會因此而改變的!如果非要計算,也可以拿單個家庭作為研究物件來進行期望值的計算,可以發現其實這還是一個等比數列,最後生男生女的期望值都是相等的,都是1個,也就是說,在這種策略下平均每家要了兩個孩子,一男一女。
計算方法如下:
生一個孩子就不生的概率是0.5,生兩個孩子就不生的概率是0.5*0.5,所以,
生孩子個數的期望值是:
1*0.5+2*0.5*0.5+3*0.5*0.5*0.5+……=2
生男孩的期望值是:
1*0.5+1*0.5*0.5+1*0.5*0.5*0.5+……=1
或者也可以寫程式碼去做個實驗:
<span style="font-size:14px;">#include <iostream>
#include <time.h>
#include <stdlib.h>
using namespace std;
int n[2];
int main()
{
srand(time(0));
for (int i=1;i<=100000000;i++)
{
int t=rand()%2;
n[t]++;
while (t!=0)
{
t=rand()%2;
n[t]++;
}
}
cout<<n[0]<<' '<<n[1]<<endl;
}
</span>
五、袋子足夠大,袋子裡面有三種顏色的球。數量都是一樣的,摸出來的概率是一樣的。小明隨便摸出來兩個,然後看了一眼說至少有一個是紅的。問,小明摸出來兩個紅球的概率是多少??
答案:兩個紅色的組合數有一種,一紅一其他的組合數有2+2=4種。
因此,兩個紅球的概率=1/(1+4)=5種