1.【百度】給定一個無序數組,其中有一個元素個數超過數組元素個數的一半,請找出該元素,要求時間複雜度爲O(n),空間複雜度爲O(1)。面試
2.【360】給定一個無序數組,尋找第k大的元素,要求時間複雜度爲O(n)。數組
3.【XX】給定一個含有2*k+1個元素的無序數組,其中有k個元素出現兩次,有1個元素出現一次,請找出該元素,要求時間複雜度爲O(n)。ui
4.【XX】給定一個含有2*k+2個元素的無序數組,其中有k個元素出現兩次,有2個元素出現一次,請找出該元素,要求時間複雜度爲O(n)。spa
5.【XX】給定一個含有4*k+2個元素的無序數組,其中有k個元素出現四次,有1個元素出現兩次,請找出該元素,要求時間複雜度爲O(n)。
code
6.【XX】給定兩個無序數組X[m],Y[n],求兩個數組按遞增形式合併後,位於中間的元素,要求時間複雜度爲O(n)。blog
7.【羣碩】編寫一個程序判斷一個數是不是迴文素數(迴文素數就是從左向右讀與從右向左讀徹底同樣的素數,好比11,101,131,151,313,...)遞歸
分析:主要是迴文的判斷,是否素數是很好判斷的。ip
判斷迴文,最簡單就是將數字翻轉過來,而後判斷是否相等便可。io
#include <stdio.h> #include <stdlib.h> int is_sushu(int val){ int k; if(val<0||val%2==0) return -1; if(val==1||val==2) return 0; for(k=3; k<val/2; k+=2) if(val%k==0) return -1; return 0; } int is_huiwen(int val){ int temp=val; int k=0; while(temp){ k=k*10+temp%10; temp = temp/10; } if(k==val) return 0; else return -1; } int main(void){ int val; scanf("%d", &val); if(is_sushu(val)==0&&is_huiwen(val)==0) printf("%d is a huiwensushu\n", val); else printf("%d is not a huiwensushu\n", val); system("pause"); return 0; }
8.【羣碩】輸入兩個整數n和m,從數列1,2,3,...,n中隨意取幾個數,使其和等於m,要求將其中全部的可能組合列出來。class
題目木有說明是否能夠重複取值,但假設能夠取重複數,可知最多能夠取m個數,m*1=m嘛,範圍爲[1, ∞)若是不可取重複數,那麼,至少須要取k個數((1+k)*k/2≥m),而最大值則爲(n+1)*n/2,因此取值範圍爲[1, (n+1)*n/2]。
①能夠取重複數
那麼最多有m層遞歸,但層數不肯定,沒法用循環,因此仍是用遞歸裏面的回溯法吧。
只要保證下一層遞歸取值爲≥上一層遞歸的取值,則能夠確保結果的不重複性,由於最多能夠取m個數,那麼分配m個存儲空間保存結果便可。
find_two表示從1,...,n中取兩個數a,b使得a+b=m,
那麼當取定a=k時,再從1,...,n中尋找兩個數a',b'使得a'+b'=m-k便可,這樣就成爲子問題了。
遞歸的結束條件則爲當求和的值m<=0則直接結束,若是m≤n時,還能夠找到一個數的狀況,因此不要遺漏便可。
#include <stdio.h> #include <stdlib.h> static int *num; static int len; void find_two(int m, int n, int s){ int k; if(m<=0) return; if(m<=n&&m>=s){ for(k=0; k<len; k++){ printf("%d ", *(num+k)); } printf("%d", m); printf("\n"); } for(k=s; k<=n; k++){ if(k>m) break; *(num+len++)=k; find_two(m-k, n, k); len--; } } int main(void){ int m,n; scanf("%d", &n); scanf("%d", &m); num = (int*)calloc(m, sizeof(int)); len = 0; find_two(m, n, 1); system("pause"); return 0; }
②不可取重複數(原理與①類似,在①的代碼上稍做修改便可)
#include <stdio.h> #include <stdlib.h> static int *num; static int len; void find_two(int m, int n, int s){ int k; if(m<=0) return; if(m<=n&&m>s){ for(k=0; k<len; k++){ printf("%d ", *(num+k)); } printf("%d", m); printf("\n"); } for(k=s+1; k<=n; k++){ if(k>m) break; *(num+len++)=k; find_two(m-k, n, k); len--; } } int main(void){ int m,n; scanf("%d", &n); scanf("%d", &m); num = (int*)calloc(m, sizeof(int)); len = 0; find_two(m, n, 0); system("pause"); return 0; }
另外一種代碼風格:
依然是遞歸方法,對於當前求和值爲sum,先取值k,剩餘sum+k,若sum+k>m,則無需再取,直接退回上層;若sum+k<m,則繼續取值(爲避免重複,取值須要大於k,即從k+1開始取);若sum+k==m則打印結果。這種風格略顯麻煩。
#include <stdio.h> #include <stdlib.h> static int *num; void dis_zuhe(int s, int sum, int m, int n){ //s上一層取值,此層取值由s+1開始 int k; if(sum==m){ for(k=0; k<n; k++){ if(*(num+k)) printf("%d ", k+1); } printf("\n"); } else{ for(k=s+1; k<=n; k++){ sum+=k; *(num+k-1)=1; if(sum>m){ sum-=k; *(num+k-1)=0; break; } dis_zuhe(k, sum, m, n); sum-=k; *(num+k-1)=0; } } } void find(int n, int m){ int summax; int sum=0; summax = (n+1)*n/2; //don't care about overflow if(summax<m) return; dis_zuhe(0, sum, m, n); } int main(void){ int m,n; scanf("%d", &n); scanf("%d", &m); num = (int*)calloc(n, sizeof(int)); find(n, m); system("pause"); return 0; }
9.【聯發科】有10盒藥,每盒有56顆藥片,其中有一盒藥片由於過時而致使吸取空氣水分使得每顆藥片增長了1g,如今有一個電子天平,並且能夠準確讀出兩邊相差重量(準確到g),如何只使用一次天平找出那盒過時的藥?
分析:
爲了區分每盒藥,那麼分別從第一盒到第九盒藥中取出1,2,3,4,...,9顆藥片,第十盒藥則取出前面9盒取出的藥片數之和(即45顆);
前9盒藥放在天平左邊,第十盒放在天平右邊;
若是第一盒過時,則左邊天平必比右邊天平重1g;若是第i盒(i∈[1,9])過時,則左邊天平比右邊天平重ig;若是第10盒過時,則右邊天平更爲重些。
10. 【XX】求階乘之和S=1!+2!+...+n!的結果末尾6位數,n範圍爲2≤n≤100000
分析:
安裝常規循環計算,除了要解決溢出翻轉問題還須要考慮效率的問題。
此題爲求解n!末尾0的位數的變種題,當p!末尾有6個0時,任意m>p,m!末尾均有6個0,由於m!=p!*(p+1)*...*m,所以先找出末尾6個0首次出現的階乘便可。
由以前的面試題能夠得知,末尾有6個0時,將恰好有6個因子5,那麼包含這6個因子5的數分別爲五、十、1五、20、25(5*5有兩個5),因此25!以後的階乘對結果不起任何影響,這樣能夠大大下降計算量了。