筆試——編程算法題


 1. 2016 "一戰通offer"互聯網實習季編程挑戰 編程題4 串珠子

題目鏈接

現在A和B在玩一個游戲,這個游戲首先給了他們很多珠子,珠子有兩種顏色,一種藍色,一種黃色,我們假定兩種珠子都有無限多。A需要選擇n顆珠子(n為奇數),然后由B串成一串項鏈(順序由B確定,這里的項鏈也就是一個環)。假如在最后串成的項鏈中,A能夠找到兩個不同位置的藍色珠子,並在這兩處把這個項鏈斷開成兩段,其中一段恰好長度為(n+1)/2那么A就勝利了,注意這里為整數截斷除法且這個長度是不包括選出的兩顆珠子的。現在請你計算出A至少要選擇多少顆藍色珠子,才能保證無論B怎么串,他都能獲勝。舉個例子,當A選了7顆珠子,其中有3顆藍珠子,那么如果B串的項鏈為"藍藍紅紅紅紅藍",則A能獲勝,若B串的項鏈為"藍藍紅紅藍紅紅",則A不能獲勝。

輸入描述:

給定一個整數n,為A要選出的珠子顆數.

輸出描述:

請返回A至少要選的藍珠子顆數。
輸入例子:
7
輸出例子:
4

這題是道公式推理題,有人這樣做也能過
 if(n%3==0)
      n=(n-1)/2;
 else n=(n+1)/2;
 return n;

苦思許久,未能想出為啥這樣做一定正確。 於是只有用自己的土辦法來推。

問題等價於: 給出珠子總數n,求最大的藍珠子數x且滿足無論用什么辦法排列都無法在移除兩個藍珠子后剩下某段長度為(n+1)/2。

最后的答案,

A至少要選的藍珠子顆數 = x+1

定理:

在合法狀態下:( 也就是移除任意兩個藍珠子,都無法得到(n+1)/2的段 )

1.設k = (n-3)/2,如果在i位置為藍珠子,則(i+k)%n和(i-k+n)%n的位置必須為黃珠子

證明:

假設i位置為藍珠子,且(i+k)%n的位置也為藍珠子,則在這兩個珠子之間(短的那段)共有k+1個珠子,則將這段移除后剩下來的一段長度為:n-(k+1) = n - (n-1)/2=(n+1)/2

同理(i-k+n)%n的情況。定理1即證。

 

然后可以知道所有相差k的,必然組成一個大環。(i,i+k,i+2k,i+3k .... (i==(i+xk)%n) ) 只需要分別處理幾個環即可。對於任意一個環,長度為L,最多可以放的藍珠子數很容易知道,為L/2(只要在這個環藍黃珠子相間的穿)。 那么這題就可以這樣做了。

class Chain {
public:
    int findK(int n) {
        // write code here
        int ret = 0;
        int key = (n-3)/2;
        int mark[100100];
        int i = 0;
        memset(mark,0,sizeof(mark));
        while(1)
        {
            int flag=0;
            for(int j=0;j<n;j++)
            {
                if(mark[j] == 0)
                {
                    flag = 1;
                    i = j;
                    break;
                }
            }
            if(flag == 0) break;
            int cnt=0;
            while(mark[i] == 0)
            {
                cnt++;
                mark[i] = 1;
                i += key;
                i %= n;
            }
            ret += cnt/2;
        }
        return ret+1;
    }
};

然后在分析最開始給出公式解法。

有一種假設,對於n為奇數,且不被3整除,則(n-3)/2與n的GCD 為1

雖然我還沒證明,但是我驗證了10^8的數發現都是正確的。

對於這種情況,只能找到一個這樣的環,所以結果就為 (n+1)/2

而對於n為奇數,能被3整除,(n-3)/2與n的GCD不為1,所以知道可以找到兩個這種環,(我猜測只能有兩個環)所以結果為(n-1)/2

 

2. 快速排序——代碼以及平均復雜度分析

void quick_sort(int *g,int l,int r)
{
    if(l >= r) return ;
    int mid = rand()%(r-l+1)+l;
    swap(g[l],g[mid]);
    int pl=l,pr=r;
    while(pl<pr)
    {
        while(pl<pr && g[pr]>g[l]) pr--;
        while(pl<pr && g[pl]<=g[l]) pl++;
        swap(g[pl],g[pr]);
    }
    swap(g[l],g[pl]);//這時只知道g[pl]<=g[l]
    quick_sort(g,l,pl-1);
    quick_sort(g,pl+1,r);
}

關於平均復雜度,找了半天資料發現《算法導論》使用概率的證明方法實在是簡潔明了,瞬間就懂了。

已知待排序的數組為a[1,...,n]

假設已經將a排好序得到g[1,...,n]

設pi,j 為g[i]與g[j]需要進行比較的概率。

則總的期望比較次數(平均復雜度)為Σ(i=1...n)Σ(j=i+1...n)pi,j 

而pi,j = 2/(j-i+1)  (只有當選擇g[i]或g[j]為基准點時,g[i]和g[j]才會進行比較.而選到g[k](i<k<j)時,g[i]與g[j]不會進行比較。且選到其它點時不影響)

然后根據調和級數加和為log(n),最后可以得到平均復雜度為O( nlog(n) ) 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM