小程序员的趣味题(一)

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
#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         mid = (lo + hi + 1) / 2;//求上界要保证能取到最大值
14         if(arr[mid] <= x)
15         {
16             if(arr[mid] == x)//x在arr中出现过
17                 flag = true;
18             lo = mid;
19         }
20         else
21         {
22             hi = mid - 1;
23         }
24     }
25     if(flag)
26         return lo;
27     return -1;
28 }
29 
30 //求下界,返回值是-1表示在arr中没找到x
31 int lower_bound(int *arr,int n,int x)
32 {
33     bool flag = false;//用于判断x是否存在于arr中
34     int lo,hi,mid;
35     lo = 0 ; hi = n-1;    
36     while(lo < hi)
37     {
38         mid = (lo + hi) / 2;
39         if(arr[mid] >= x)
40         {
41             if(arr[mid] == x)
42                 flag = true;
43             hi = mid;
44         }
45         else
46         {
47             lo = mid + 1;
48         }
49     }
50     if(flag)
51         return lo;
52     return -1;
53 }
54 //计算x在arr中的出现次数
55 void count(int *arr,int n,int x)
56 {
57     int hi = upper_bound(arr,n,x);
58     int lo = lower_bound(arr,n,x);
59     if(hi != -1)
60     {
61         cout<<x<<" 在arr中出现了 "<<hi - lo +1 <<" 次 !!"<<endl;
62     }
63     else
64     {
65         cout<<x<<" 在arr中出现了 0 次 !!"<<endl;
66     }
67 }
68 int main()
69 {
70     int arr[] = {1,2,2,3,5,6};
71     count(arr,6,4);
72     count(arr,6,2);
73     return 0;
74 }
复制代码
 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         mid = (lo + hi + 1) / 2;//求上界要保证能取到最大值
14         if(arr[mid] <= x)
15         {
16             if(arr[mid] == x)//x在arr中出现过
17                 flag = true;
18             lo = mid;
19         }
20         else
21         {
22             hi = mid - 1;
23         }
24     }
25     if(flag)
26         return lo;
27     return -1;
28 }
29 
30 //求下界,返回值是-1表示在arr中没找到x
31 int lower_bound(int *arr,int n,int x)
32 {
33     bool flag = false;//用于判断x是否存在于arr中
34     int lo,hi,mid;
35     lo = 0 ; hi = n-1;    
36     while(lo < hi)
37     {
38         mid = (lo + hi) / 2;
39         if(arr[mid] >= x)
40         {
41             if(arr[mid] == x)
42                 flag = true;
43             hi = mid;
44         }
45         else
46         {
47             lo = mid + 1;
48         }
49     }
50     if(flag)
51         return lo;
52     return -1;
53 }
54 //计算x在arr中的出现次数
55 void count(int *arr,int n,int x)
56 {
57     int hi = upper_bound(arr,n,x);
58     int lo = lower_bound(arr,n,x);
59     if(hi != -1)
60     {
61         cout<<x<<" 在arr中出现了 "<<hi - lo +1 <<" 次 !!"<<endl;
62     }
63     else
64     {
65         cout<<x<<" 在arr中出现了 0 次 !!"<<endl;
66     }
67 }
68 int main()
69 {
70     int arr[] = {1,2,2,3,5,6};
71     count(arr,6,4);
72     count(arr,6,2);
73     return 0;
74 }
复制代码

小结:有人也提到了这样解法,即:先利用二分找到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 }
复制代码

 

 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 }
复制代码
1 int rand7()
2 {
3     int i;
4     //直到产生6~26之间的数跳出循环
5     while((i=rand5()*5+rand5()) > 26) ;
6     return (i-3)/3;
7 }
复制代码

 

 

posted @ 2012-08-07 18:19  超级塞亚人  阅读(308)  评论(0编辑  收藏  举报