筆試——編程算法題

 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不能獲勝。數組

輸入描述:ui

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

輸出描述:spa

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

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

苦思許久,未能想出爲啥這樣作必定正確。 因而只有用本身的土辦法來推。code

問題等價於: 給出珠子總數n,求最大的藍珠子數x且知足不管用什麼辦法排列都沒法在移除兩個藍珠子後剩下某段長度爲(n+1)/2。blog

最後的答案,排序

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

定理:遊戲

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

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) ) 

相關文章
相關標籤/搜索