日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法题集-2

發布時間:2025/4/5 编程问答 17 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法题集-2 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

K階錦標賽算法

一個賽馬場有100匹馬,5條賽道,至少要比賽多少場才能選出跑得最快的10匹馬?

步驟:

1. 將100匹馬分成20次比賽,每次5匹馬,并保存每次比賽的結果(即第1名到第5名的順序)

2. 從勝利的20匹馬分成4次比賽,每次5匹馬,并保存每次比賽的結果(即第1名到第5名的順序)

3. 對最后的4匹馬進行比賽,并保存每次比賽的結果(即第1名到第4名的順序)

即通過以上3個步驟,其實已經建立一個4層的樹結構。并且已經得到第1名A

4. 在4層樹結構中,挑出與A比過賽的且失敗的,且是第2名的馬(不超過5位),挑選出第2名B

在此過程中,可以想象將A刪除,并在比較過程中恢復樹結構

依次輪推,直至找出前10名

總的比較次數為:

選出第一名:20+4+1

選出第二名:1

選出第三名:1

...

選出第十名:1

總次數:34次

?

問題描述:一個骰子有6面,概率均勻,我有7件事要隨機均勻選擇,用最少的扔擲次數如何仍?

問題擴展:如果我有4件事,5件事,8件事,9件事,10件事 …… n件事要選擇,那么我如何用最少的扔擲次數來做到均勻分布?

思路:

注意問題中的關鍵字:(1) 最少扔擲的次數 (2) 要求概率均勻分布

用容易理解的方式再將問題描述一遍:我們周末決定去聚餐,此時有6家備選飯店供我們選擇,為了公平,用骰子扔擲一次即可以隨機選出一家飯店。

但是,此時如果有7家備選飯店,同樣要做到公平,我們如何用6個面的骰子選擇去哪家飯店呢?

方法:

用骰子扔2次,可以得到 [7, 42] 區間中的一個數(視為6進制),假設扔擲的數表示為m,如果 m=7 則舍棄,否則將 m mod 7 得到的數即為最終結果。

PS: m=7 時,會使得 0 的概率變大,所以要舍棄。

將上述表述再換種方式理解,用骰子扔2次,可以得到 [7, 42] 區間中的一個數,即此時得到了 36 個隨機數,對應區間 [1, 36]。因此,假設扔擲的數表示為m,如果 m=36 則舍棄,否則將 m mod 7 得到的數即為最終結果。同理,當 m=36 時,會使得 1 的概率變大,所以要舍棄。

結論:

(1) 靈活使用N進制的思想,雖然生活中多用10進制。本題使用的是6進制的思想,即表示為: result = Y * 6 + X,其中,X 表示第一次扔擲的點數,Y 表示第二次扔擲的點數。

(2) 使用求和的方法不滿足概率均勻分布,求和的結果屬于正態分布,中間值的概率最大,出現最大值和最小值的概率最小。

?

設計一個算法找到數組中兩個元素相加等于指定數的所有組合

思路:將數組排序,然后用兩個指向數組的指針,一個從前往后,一個從后往前,記為first和last,如果 fist + last < sum 則將fist向前移動,如果fist + last > sum,則last向后移動。

#if 1 #include <vector> #include <iostream> #include <algorithm> #include <iterator> #include <cstdlib> using namespace std; int main(){vector<int> iv;int N=20;// srand(time(0));for(int i=0;i<N;i++){int val=rand()%1000;if(val&0x1)val=-val;iv.push_back(val);}int s=109;//rand()%10000;copy(iv.begin(),iv.end(),ostream_iterator<int>(cout," "));cout<<endl;sort(iv.begin(),iv.end());copy(iv.begin(),iv.end(),ostream_iterator<int>(cout," "));cout<<endl;vector<int>::const_iterator ite1=iv.begin(),ite2=iv.end()-1;while(ite1!=ite2){int sum=*ite1+*ite2;if(sum>s)--ite2;else if(sum<s)++ite1;else {cout<<*ite1<<' '<<*ite2<<endl;++ite1;--ite2;}} } #endif

18. 卡特蘭數

http://baike.baidu.com/view/2499752.htm

19. LIS最長遞增子序列

請給出一個O(nlogn)的算法,使之能夠找出一個n個數的序列中最長的單調遞增子序列。

這是算法導論中的一道課后題。

解法一:利用求最長公共子序列的思想,將n個數的序列A先排序形成一個有序的序列B,然后利用動態規劃的思想求A與B的最長公共子序列,得到的最長公共子序列就是所求的解。但是我們知道最長公共子序列的解法是O(n2),所以不滿足題目要求,此法不通。

解法二:對包含n個數的序列A,我們使用一個數組C,其中C[i]記錄長度為i的所有單調遞增子序列的最小的元素(可能說的不清楚,舉例說明比如A有3個長為2的單調遞增子序列1,2;3,4;5,6;那么C[2]的值就是2,記錄的是最小的那個子序列的最后一個元素)。具體的遍歷過程是對于一個元素A[i],通過二分查找C(因為C是有序數組),獲取A[i]的位置flag,比較A[i]與C[flag]的大小,如果小于C[falg]用A[i]替換C[flag],如果大于用A[i]替換C[flag+1]。這樣遍歷一遍就能得到數組A的最長的公共子序列的長度,但是要獲得最長公共子序列的組成,需要利用第一次遍歷獲得長度,再遍歷一次,在給定的長度時將C中的元素拷貝出來,防止后邊可能進行的破壞。雖然需要遍歷兩邊但是滿足時間復雜度的要求,大家有更好的方法歡迎討論。

?

問題描述:兩個數組a[N],b[N],其中A[N]的各個元素值已知,現給b[i]賦值,b[i] = a[0]*a[1]*a[2]...*a[N-1]/a[i];

要求:

1.不準用除法運算

2.除了循環計數值,a[N],b[N]外,不準再用其他任何變量(包括局部變量,全局變量等)

3.滿足時間復雜度O(n),空間復雜度O(1)

#include <iostream> #include <cstdlib> using namespace std; const int N=10; int main1(int* a) {int i;int b[N];b[0] = 1;for(i = 1; i < N; i++){b[0] *= a[i - 1];b[i] = b[0];}b[0] = 1;for(i = N-2; i > 0; i--){b[0] *= a[i + 1];b[i] *= b[0];}b[0] *= a[1];for(i = 0; i < N; i++){cout << b[i] << " ";}cout << endl;return 0; } int main2(int *a){int i;int b[N];b[N-1]=1;for(int i=1;i<N-1;i++){b[N-1]*=a[i-1];b[i]=b[N-1];}b[N-1]*=a[N-2];b[0]=1;for(int i=N-2;i>0;i--){b[0]*=a[i+1];b[i]*=b[0];}b[0]*=a[1];for(i = 0; i < N; i++) {cout << b[i] << " ";}cout << endl; } int main(){srand(time(0));int a[N];for(int i=0;i<N;i++) {int val;while((val=rand()%10)==0);a[i]=val;}main1(a);main2(a); } 騰訊筆試題:計算下面函數的結果: static int ack(int m,int n){if(m==0){return n+1;}else if(n==0){return ack(m-1,1);}else{return ack(m-1,ack(m,n-1));} }

?

騰訊面試題:1-20的兩個數把和告訴A,積告訴B,A說不知道是多少,B也說不知道,這時A說我知道了,B接著說我也知道了,問這兩個數是多少?

設和為S,積為M。

首先,A:我不知道。

說明:S可以分解成多個組合,而2=1+1,3=1+2,40=20+20,39=19+20,只有一種分解方式,因此S應屬于[4,38]集合。

其次,B:我也不知道。

說明:M也可以分解成多個組合,因此M不是質數。

再者,A:我現在知道了。

說明:S分解方式中只有一個相乘之后是合數,其他分解方式相乘之后都是質數。這樣,A才能根據B說不知道,而排出所有相乘是質數(M是質數,分解方式只有一種:1*質數)的可能,剩下的一個相乘之后是合數的組合就是A所得到的解。

而相乘之后是質數的:只有1*質數 = 質數!

1-20的所有質數:T = {2, 3, 5, 7, 11, 13, 17, 19}。

設x為T中的任意一個質數。那么,S的可能取值集合:{2+1, 3+1, 5+1, 7+1, 11+1, 13+1, 17+1, 19+1},即:SS = {3, 4, 6, 8, 12, 14, 18, 20}

S= 3時:3不在【4,38】集合,排除;

S= 4時:4=2+2=1+3,(2,2)相乘為4(非質數,滿足條件),(1,3)相乘為3(質數,排除);

S= 6時:6=1+5=2+4=3+3,相乘分別為5,8,9,出現兩個合數,排除;

其他值都是存在多個合數分解的情況,因此均排除了。

因此,A得到的解是2和2.

最后,B:我也知道了。

說明:B根據自己已知的M值,站在A的立場思考,能夠獲得M=4的結果,現在驗證如下:

M=4=2*2=1*4,相加結果為4,5.而5不在SS集合之中,因此結果為2和2.

因此,最終答案為2和2.

以上給出的分析是假設這兩個數是可以相同的。

如果認為這兩個數不同,那又應該是哪兩個數呢?

還是按照上面的步驟來進行分析:

首先,A:我不知道。

說明:S有多個分解方式。S屬于【5,37】.

其次,B:我不知道。

說明:M有多種分解方式。

再者,A:我知道這兩個數了。

說明:

S分解方式中只有一個相乘之后是合數,其他分解方式相乘之后的積僅有一種分解方式!這樣,A才能根據B說不知道,而排出所有相乘是質數(M是質數,分解方式只有一種:1*質數)的可能,剩下的一個相乘之后是合數的組合就是A所得到的解。

那么,S的可能取值集合:{3,4,5,......,37}

S= 3時:3不在【5,38】集合,排除;

S= 4時:4=1+3,只有一種分解方式,排除;

S=5時:5=1+4=2+3,相乘分別為4,8,4=1*4僅有一種分解方式排除,8=1*8=2*4滿足,得到一個解。

S= 6時:6=1+5=2+4,相乘分別為5,8,顯然也滿足。

其他值都是存在多個合數分解的情況,因此均排除了。

因此,解為2和3 或 2和4

最后,B:我也知道了。

說明:

B站在A立場得知結果。驗證如下:

如果為2和3,則積為6,和為5。此時,5=1+4=2+3,4僅有一種分解方式,A能夠確定為2和3;6=1*6=2*3,相加為7,5,此時7=1+6=2+5=3+4,相乘后為6,10,12,無法確定唯一解,舍掉1,6的解;而5=1+4=2+3,相乘后為4,6,舍掉4,有解2和3.

如果為2和4,則積為8,和為6.此時,6=1+5=2+4,5僅有一種分解方式,A能夠確定為2和4. 8=1*8=2*4,相加為9,6,此時9=1+8=2+7=3+6=4+5,無法確定唯一解,舍掉1和8的解;而6=1+5=2+4,相乘后為5,6,舍掉5,有解2和4.

因此,最終解為2和3 或 2和4 。

?

趣題:從1到4000中各位數字之和能被4整除的有多少個?

一個小學奧數老師給我講了一道小學奧數題,這是他在上課時遇到的:從 1 到 4000 中,各位數字之和能被 4 整除的有多少個?

注意,問題可能沒有你想的那么簡單,滿足要求的數分布得并沒有那么規則。 1 、 2 、 3 、 4 里有一個滿足要求的數, 5 、 6 、 7 、 8 里也有一個滿足要求的數,但是 9 、 10 、 11 、 12 里就沒有了。

盡管如此,這個問題仍然有一個秒殺解。你能多快想到?

答案就是 1000 。首先, 0 和 4000 都是滿足要求的數,因而我們不去看 1 到 4000 中有多少個滿足要求的數,轉而去看 0 到 3999 中有多少個滿足要求的數,這對答案不會有影響。注意到,如果固定了末三位,比如說 618 ,那么在 0618 、 1618 、 2618 、 3618 這四個數中,有且僅有一個數滿足,其各位數字之和能被 4 整除。考慮從 000 到 999 這 1000 個可能的末三位組合,每一個組合都唯一地對應了一個滿足要求的四位數,因此問題的答案就是 1000 。

真正有趣的事情在后面呢。一個小朋友舉手說:“老師,我明白了,按照這個道理,從 1 到 3000 里各位數字之和能被 3 整除的數也是 1000 個。”另一個小朋友說:“廢話,各位數字之和能被 3 整除就表明整個數能被 3 整除,在 1 到 3000 里這樣的數當然有 1000 個嘛!”全班哄堂大笑。

轉自:http://www.matrix67.com/blog/archives/4644

題目:10G 個整數,亂序排列,要求找出中位數。內存限制為 2G。

解答:

拿到此題目首先考慮的是內存的限制,因而無法用快速排序或是部分排序。若是求的是最大值或最小值,或是K小的值(k<2G)則可以采用堆排序O(NlogK)。但現在是求中位數即排在第5G和5G+1的數

算法思路分析:假設是無符號整數,

第一步: 借鑒桶排序的思路,因為整數為32位,我們先按高16位2^16=64K進行計數,即分成64K段,這樣需要的計數數組大小為2^16,若數組類型為int型,存在缺點,若10G的數都是相同,這樣數組存的計數最大為2^32=4G,就會出現溢出,所以數組類型采用long long8字節型。占用內存為2^16*8B=518KB。而內存給了2G,可見利用得過少,表明還有很大的改進空間。 改進:分成2G/8B=2^28=256M段,這樣段越多,第二步掃描分析的數據就越少。

long long Counter[1 < <28];//256M桶 unsigned int x; memset(Counter,0,sizeof(Counter)); foreachnumber(x) {Counter[x>>4]++; //高28位 } long long sum=0; for(i=0;i <1 < <28;i++) {sum+=Counter[i];if(sum>=5LL < <30)break;//找到中位數所在的段 } sum-=5LL < <30; sum=Counter[i]-sum;//為達到5G,中位數所在的段需要的個數

第二步:前步已把10G數據按高28位分到了256M桶中,且已經找到中位數在哪一段,只要把此段按低4位分到16個段中,即可以找到

int segment=i; memset(Counter,0,sizeof(Counter)); foreachnumber(x) {if((x>>16)==segment){Counter[x&(~((-1) < <16))]++; //低4位。 -1的8位二進制表示為11111111 } } long long lsum=0; for(i=0;i <1 < <4;i++) {lsum+=Counter[i];if(lsum>=sum)break; } int keynum = (segment<<4)|(i);

總共只要讀兩遍整數,對每個整數也只是常數時間的操作,總體來說是線性時間

若是有符號的整數,只需改變映射即可。

參考:http://grachel1986.blog.163.com/blog/static/5660389320108271179910/

轉載于:https://www.cnblogs.com/xkfz007/archive/2012/11/20/2779186.html

總結

以上是生活随笔為你收集整理的算法题集-2的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。