常見算法題

一、維護O(1)時間查找最大元素的棧

問題描述:一個棧stack,具有push和pop操作,其時間複雜度皆爲O(1)。設計算法max操作,

求棧中的最大值,該操作的時間複雜度也要求爲O(1)。

可以修改棧的存儲方式,push,pop的操作,但是要保證O(1)的時間複雜度,空間時間複雜

度無要求。

 

可以創建一個類,類裏有兩個棧,一個棧S維持正常的push、pop操作,另一個Sm保存當前的最大值

假設元素以5,4,1,2,3,10,9,8,6,7,15順序入棧,則兩個棧中存儲的元素如下圖所示:

S    5    4    1    2    3    10    9    8    6    7    15

Sm 5    10  15

struct max_stack{
    stack<int> s1;
    stack<int> sm;
};
max_stack s;
void my_push(int k) {
    if(!s.s1.empty()){
        if(k>s.sm.top()) s.sm.push(k);
        s.s1.push(k);
    } else {
        s.s1.push(k);   s.sm.push(k);
    }
}
void my_pop() {
    if(!s.s1.empty()) {
        if(s.s1.top()==s.sm.top())  s.sm.pop();
        s.s1.pop();
    }
}
int my_max() {
    if(!s.s1.empty()) {
        return s.sm.top();
    }
}

二、約瑟夫環問題

瑟夫環問題的原來描述爲,設有編號爲1,2,……,n的n(n>0)個人圍成一個圈,從第1個人

開始報數,報到m時停止報數,報m的人出圈,再從他的下一個人起重新報數,報到m時停止

報數,報m的出圈,……,如此下去,直到所有人全部出圈爲止。當任意給定n和m後,設計

算法求n個人出圈的次序。換一種表述如下

問題描述:n個人(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人繼續從0開始

報數。求勝利者的編號。

具體數學上給出通項公式:

f(0)=0       

f(n)=(f(n-1)+m)%n    ,    (n>1)

int joseph(int n,int m) {
    int *f=new int[n+1];
    f[0]=f[1]=0;
    for(int i=2;i<n+1;i++) 
        f[i]=(f[i-1]+m)%i;
    int result=f[n];
    delete []f;
    return result;
}

如果求解原表述的解,只需要將result加1即可。

三、尋找明星

問題描述:有個聚會有N人蔘加,其中N-1個是羣衆。1個是明星。其中所有羣衆都認識明星,

明星不認識任何羣衆,羣衆之前是否認識不知道。

假設有個機器人能問問題A是否認識B?時間複雜度爲O(1),那麼設計一個算法用最小的復

雜度找出明星。

從問題的描述中可以知道,對於任意兩個人A、B,如果A認識B那麼A一定不是明星;如果A不

認識B,那麼B一定不是明星。將所有人存儲在數組中,每次比較詢問A[0]是否認識A[1],將一

定不是明星的人放在數組的最後,並且在以後可以不用管了。代碼描述如下

int famous(int A[],int n) {
    int j=n;
    while(j>1) {
        if(A[0] knows A[1]) 
            swap(A[0],A[1]);
        swap(A[1],A[--j]);
    }
    return A[0];
}

由於詢問和交換的時間複雜度是O(1),while循環進行了n-1次,所以時間複雜度是O(n).

四、最小交流次數

問題描述:有n個戰士其中n>4他們手中都有不同的情報,假設每個人通過交流能過得雙方所有

的情報。設計一個算法使得用最少的交流次數使得所有的戰士都獲得全部的情報,給出算法並

給出最小交流次數?

 

可以建立遞推式:

                       f(4)=4

                       f(n)=f(n-1)+2  ,  n>4

假設在戰士人數是n-1時需要f(n-1)次交流,則增加一個人時,如下步驟進行:

1、第n個戰士和前面任意一個戰士交流一次

2、前n-1個戰士互相交流,使得前面n-1個戰士都有所有戰士獲得的情報

3、第n個戰士和前面任意一個戰士交流一次。

這樣n個戰士都有所有情報了。

五、數星星

問題描述:A和B晚上無聊就開始數星星。每次只能數K個(20<=k<=30)A和B輪流數。最後

誰把星星數完誰就獲勝,那麼當星星數量爲多少時候A必勝?

這是一個博弈的問題,我們可以從勝利條件出發,A必勝,那麼最後一次是A數,並且剩下星星

的個數 20<=k<=30 ,那麼如何保證呢?最後50顆由B先數,B數m顆,然後A數剩下的50-m

顆。好了,那麼第一次A數的話必須保證,第一次A數完之後,剩下的個數是50的倍數。所以

案就明瞭了,星星的數量應滿足    

50k+20 <= N <=50K+30    ,    k是整數

六、求連續子數組的最大和

這是一個動態規劃問題遞推式爲

M(i)=max{M(i-1)+a(i),a(i)},i>0

int max_sub_sum(int *A,int n) {
    int thissum=0,maxsum=0;
    for(int i=0;i<n;i++) {
        thissum+=A[i];
        if(thissum>maxsum)    maxsum=thissum;
        if(thisum<0)          thisum=0;
    }
    return maxsum;
}

七、二分查找

用二分法查找已排序的大小爲n的數組A是否存在value,如果存在返回下標,否則返回-1。

int b_search(int *A,int n,int value) {
    int low=0,high=n-1;
    while(low<=high) {
        int mid=(low+high)/2;
        if(A[mid]==value)        return mid;
        else if(A[mid]>value)    high=mid-1;
        else                     low=mid+1;
    }
    return -1;
}

轉自:http://blog.csdn.net/xhl9317273572010xhl/article/details/8911736

八、分糖果
有n個小朋友坐成一圈,每人有Ai個糖果。每人只能給左右兩人傳遞糖果。每人每次傳遞一個糖果代價爲1,求使所有人獲得均等糖果的最小代價。設Xi爲第i-1個小朋友分給第i個小朋友的糖果數,G爲最後的平均數。其中X1爲第n個小朋友分給第1個小朋友的糖果數。

A1 +X1 + X2 = G

A2 + X2 - X3 = G

.

An + Xn - X1 = G

解得

X1 = X1

X2 = A1 - G - X1

X3 = A1 + A2 - G - G + X1

.

Xn = A(n-1)+A(n-2)+...A2+A1 - (n -1)* G + X1

則總開銷爲:|X1|+|X2|+...+|Xn| =|X1|+ |A1-G+X1| + |A2+A1-2*G+X1| + ... +|A(n-1)+A(n-2)+...A2+A1 - (n -1)* G + X1|

設s[i]=Ai+ ... +A1- i*G; 則上式=|X1| + ∑|s[i]+X1|    ,1=< i<=n-1

設k爲第一個分給第n個的數量爲k,則k=-X1,上式爲:|k| + ∑|s[i]-k| ,1=< i<=n-1

要使上式值最小,則k爲0, s[1], s[2], ......s[n-1]的中位數。

這主要是利用了中位數的一個性質:數組中數與中位數差的絕對值和最小。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <algorithm>
 4 using namespace std;
 5 const long long N = 2001000;
 6 long long a[N], s[N], tar[N], n;
 7 int main ()
 8 {
 9     scanf ("%d", &n);
10     for (long long i = 1; i <= n; i ++)
11         scanf ("%d", &a[i]), s[i] = s[i - 1] + a[i];
12     long long g = s[n] / n;
13     for (long long i = 1; i < n; i ++)
14         tar[i] = i * g - s[i];
15     sort (tar + 1, tar + 1 + n);
16     long long x = n >> 1, z = abs(tar[x]);
17     for (long long i = 1; i <= n; i ++)
18         z += abs (tar[i] - tar[x]);
19     printf ("%lld\n", z);
20     return 0;
21 }
轉自:http://blog.csdn.net/stormbjm/article/details/8911396

發佈了22 篇原創文章 · 獲贊 13 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章