小程序員的趣味題(一)


1.在排序數組中,找出某整數出現的次數


問題定義:給定一個整數數組arr,數組中元素的個數是n,數組arr已經排好序,要在arr中找到某個某個整數x出現的次數,比如arr[] = {1,2,2,3,5,10},找到2的出現次數就是2。

問題分析相必看到有序數組的字樣,想到利用二分應該是很順利成章的事了。我們可以利用二分搜索求出x在arr中出現的第一個位置lo和最后一個位置hi,然后計算hi-lo+1的值就是x在arr出現的次數了,當然也有可能x並沒有在arr中出現過,這時hi和lo都等於-1。時間復雜度是兩個二分的復雜度:2*O(log n)。看看代碼是怎么實現的吧!!

相關代碼:

View Code
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 //求上屆,返回值是-1表示在arr中沒找到x
 6 int upper_bound(int *arr,int n,int x)
 7 {
 8     bool flag = false;//用於判斷x是否存在於arr中
 9     int lo,hi,mid;
10     lo = 0 ; hi = n-1;
11     while(lo <= hi)
12     {
13         if(hi - lo == 0)
14         {
15             if(arr[lo] == x)
16             {
17                 flag = true;
18             }
19             break;
20         }
21         mid = (lo + hi + 1) / 2;//求上界要保證能取到最大值
22         if(arr[mid] <= x)
23         {
24             if(arr[mid] == x)//x在arr中出現過
25                 flag = true;
26             lo = mid;
27         }
28         else
29         {
30             hi = mid - 1;
31         }
32     }
33     if(flag)
34         return lo;
35     return -1;
36 }
37 
38 //求下界,返回值是-1表示在arr中沒找到x
39 int lower_bound(int *arr,int n,int x)
40 {
41     bool flag = false;//用於判斷x是否存在於arr中
42     int lo,hi,mid;
43     lo = 0 ; hi = n-1;
44     while(lo <= hi)
45     {
46         if(hi - lo == 0)
47         {
48             if(arr[lo] == x)
49             {
50                 flag = true;
51             }
52             break;
53         }
54         mid = (lo + hi) / 2;
55         if(arr[mid] >= x)
56         {
57             if(arr[mid] == x)
58                 flag = true;
59             hi = mid;
60         }
61         else
62         {
63             lo = mid + 1;
64         }
65     }
66     if(flag)
67         return lo;
68     return -1;
69 }
70 //計算x在arr中的出現次數
71 void count(int *arr,int n,int x)
72 {
73     int hi = upper_bound(arr,n,x);
74     int lo = lower_bound(arr,n,x);
75     if(hi != -1)
76     {
77         cout<<x<<" 在數組中出現了 "<<hi - lo +1 <<" 次 !!"<<endl;
78     }
79     else
80     {
81         cout<<x<<" 在數組中出現了 0 次 !!"<<endl;
82     }
83 }
84 int main()
85 {
86     int arr1[] = {1,2,2,3,5,6};
87     count(arr1,6,4);
88     count(arr1,6,2);
89 
90     cout<<endl;
91     int arr2[] = {0,1};
92     count(arr2,2,0);
93 
94     cout<<endl;
95     int arr3[] = {1};
96     count(arr3,1,1);
97     return 0;
98 }

小結:有人也提到了這樣解法,即:先利用二分找到x在arr中出現的第一個位置lo,然后從lo下一位置開始向后直到下標達到n-1或者找到不等於x的情況結束,每前進一步,x出現的次數加 1,這樣也能求出x在arr中出現的次數,但是不要忘了這種情況,即arr = {1,1,1,1,1,1},然后x = 1,那么這時利用這種方法的時間復雜度就是O(n+log n) 了。也就是說在最壞的情況下,時間復雜度太高。

 

2.去掉字符串中多余的空格


問題描述:給定一個字符串數組,要求去掉首部和尾部的所有空格,字符串中間的空格出現1次以上只保留一個空格,比如str[] = “  Wo  shi Vincent  ”,經過處理后應為“Wo shi Vincent”。

問題分析:這是一個簡單的字符串處理的問題,顯然開頭、結尾、和中間的空格處理方式是不一樣的,我的思路是遍歷一遍字符數組,首先處理開頭的空格,方法是:全部刪除;然后是字符串中間的空格,方法是:遇到空格,值保留第一個空格;遍歷結束后,新串的最后一個字符是空格,就代表是原字符串尾部有空格存在,所以要去掉。如此一來就完事了,值需要遍歷一遍,時間復雜度是O(n)。

相關代碼:

View Code
 1 #include <iostream>
 2 #include <cstring>
 3 
 4 using namespace std;
 5 
 6 void remove_extra_space(char *str) 
 7 {
 8     int Start = 0 , End = strlen(str);
 9     int NewStart = 0;
10     while(Start < End)
11     {
12         //去掉開頭的空格
13         if(Start == 0)
14         {
15             while(Start < End && str[Start] == ' ')
16             {        
17                 Start++;
18             }
19         }
20         //處理中間的空格,多個空格值保存一個
21         if(str[Start] == ' ')
22         {
23             str[NewStart++] = str[Start++];
24             while(Start < End && str[Start] == ' ')
25             {
26                 Start++;
27             }
28         }
29         //復制非空格的字符
30         else
31         {
32             str[NewStart++] = str[Start++];    
33         }
34     }
35     //去掉末尾的空格
36     if(str[NewStart-1] == ' ')
37     {
38         str[NewStart-1] = '\0';
39     }
40 }
41 
42 int main()
43 {
44     char str[] = "  wo  shi Vincent  ";
45     remove_extra_space(str);
46     cout<<str<<"@@@@@@"<<endl;
47     return 0;
48 }

 

3.求1024!的結果中末尾有多少個0


問題分析:首先1024!呀,是多么大的一個數呢??想求出來結果然后在看末尾有多少0是不現實的,我們可以分析要求的是:末尾有多少個0。那么的0的個數有什么決定的呢?10 = 2 * 5 ,顯然一對(2 , 5)就能湊出一個末尾0,也就是說末尾0的個數是由因子2和5的個數決定的,更確切的說是由因子的個數決定的(考慮一下為什么吧!?),那么1~1024這1024個數中包含多少個因子5呢?顯然這1024個數有的包含1個因子5,有的包含兩個因子5(5^2 = 25),有得包含三個因子5(5^3 = 125),有的包含4的因子5(5^4 = 625)。那么一共包含多少因子5呢?

包含一個因子5的數有 1024 / 5 = 204 個。

包含兩個因子5的數有 1024 / 25 = 40 個。

包含三個因子5的數有 1024 / 125 = 8 個。

包含四個因子5的數有 1024 / 625 = 1 個。

也就是說1~1024這1024個數一共包含因子5的個數是: sum =  204 + 40 + 8 + 1 個。

小結:注意類似的問題可以借鑒這個題的解題思路~~~~~~

 

4.給定能隨機生成整數1到5的函數,寫出能隨機生成整數1到7的函數


問題分析:現在給了一個能隨機生成1~5的隨機函數,怎樣利用這個已知條件生成一個1~7的隨機函數呢?既然要生成的是隨機數那么生成1,2,3,4,5,6,7的概率就應該是一樣的。顯然現在光生成1~5之間的數就不夠了,我們想到應該要加大生成數的范圍,並且加大范圍的同時還要保證每個數產生的概率一樣,於是有這樣一種方法用這個表達式來擴大生成數范圍:rand5()*5+rand5(),新的數據范圍變成:6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30.並且可以看出來這個25個數出現的可能性是一樣的,於是我們可以只用6~26之間的21個數變成1~7這7個數,於是就是要每3個數對應一個數,即:

6,7,8對應1

9,10,11對應2

…………

24,25,26對應7

這種變化對應的方式是(6 - 3)/ 3 = 1,(7 - 3) / 3 = 1,(8-3) / 3 = 1.看看代碼吧:

相關代碼:

View Code
1 int rand7()
2 {
3     int i;
4     //直到產生6~26之間的數跳出循環
5     while((i=rand5()*5+rand5()) > 26) ;
6     return (i-3)/3;
7 }

 

 

 


 學習中的一點總結,歡迎拍磚哦^^


 


免責聲明!

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



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