第3章的题子勤做得不太好,有些实现可能思路不够清晰,请原谅。
3-1 分数统计 (stat) 题目: 输入一些学生的分数,哪个分数出现的次数最多?如果有多个并列,从小到大输出。任务 1: 分数均为不超过 100 的非负整数。任务 2: 分数均为不超过 100 的非负实数,但最多保留两位小数。
分析: 由于不知道人数的范围,但分数的范围是确定的,因此我们可以以分数为数组下标、次数为数组元素值,全部读入后进行比较,找出最大的。要做到并列的从小到大输出,只需要从小到大遍历一边就好了,反正数组不太大。对于任务2而言,因为“最多保留两位小数”,所以可以扩大 100 倍,变实数为整数存进数组里,输出时再变回实数。
解答: stat-1.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include  <stdio.h>  #include  <string.h>  int  score[101 ]; int  main (void ) {     int  n = 0 , max, i;     memset (score, 0 , sizeof (score));     while  (scanf ("%d" , &n) == 1 )          score[n]++;     max = score[0 ];     for  (i = 1 ; i < 101 ; i++)          if  (score[i] > max)             max = score[i];     for  (i = 0 ; i < 101 ; i++)          if  (score[i] == max)             printf ("%d\n" , i);     return  0 ; } 
stat-2.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include  <stdio.h>  #include  <string.h>  #include  <math.h>  int  score[10001 ]; int  main (void ) {     int  max, i;     double  n;     memset (score, 0 , sizeof (score));     while  (scanf ("%lf" , &n) == 1 )         score[(int )floor (n * 100  + 1e-6 )]++;      max = score[0 ];     for  (i = 1 ; i < 10001 ; i++)          if  (score[i] > max)             max = score[i];     for  (i = 0 ; i < 10001 ; i++)          if  (score[i] == max)             printf ("%.2f\n" , i/100.0 );     return  0 ; } 
3-2 单词的长度 (word) 题目: 输入若干个单词,输出它们的平均长度。单词只包含大写字母和小写字母,用一个或多个空格隔开。
解答: 未考虑输入错误的情况:
word.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include  <iostream>  #include  <string>  using  namespace  std;int  main ()     string s;     int  sum = 0 , count = 0 ;      while  (cin >> s) {         count++;         sum += s.length ();     }     cout << ((double )sum) / count << endl;     return  0 ; } 
3-3 乘积的末3位 (product) 题目: 输入若干个整数(可以是正数、负数或者零),输出它们的乘积的末 3 位。这些整数中会混入一些由大写字母组成的字符串,你的程序应当忽略它们。提示:试试看,在执行 scanf("%d") 时输入一个字符串会怎样?
分析: 子勤不是很理解这道题目的意思,所以下面的程序是把输入当成只有一行、输出不要求有正负之分来对待的。由于不用管正负,我们就可以一个个字符地判断,如果是数字就读入,然后跳过这个数字占的空间,继续查找;不是数字的话,就继续往下找,直到找到数字。
解答: product.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include  <stdio.h>  #include  <ctype.h>  #include  <string.h>  #define  MAXN 100000 char  buf[MAXN];int  main () {     int  n, i, times = 1 , slen, nlen;     fgets(buf, MAXN, stdin );     slen = strlen (buf);     for  (i = 0 ; i < slen;) {                  if  (isdigit (buf[i])) {             sscanf (buf + i, "%d" , &n);             times = ((n % 1000 ) * times) % 1000 ;             for  (nlen = 0 ; n > 0 ; n /= 10 , nlen++);              i += nlen;          } else              i++;      }     printf ("%03d\n" , times);     return  0 ; } 
3-4 计算器 (calculator) 题目: 编写程序,读入一行恰好包含一个加号、减号或乘号的表达式,输出它的值。这个运算符保证是二元运算符,且两个运算数均为不超过 100 的非负整数。运算数和运算符可以紧挨着,也可以用一个或多个空格、TAB 隔开。行首末尾均可以有空格。提示:选择合适的输入方法可以将问题简化。
样例输入:1+1
样例输出:2
样例输入:2-       5
样例输出:-3
样例输入:0    *1982
样例输出:0
解答: 题目挺长,不过做起来还算是比较好做,因为用 scanf() 很方便。
calculator.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include  <stdio.h>  int  main (void ) {     int  a, b;     char  c;     scanf ("%d %c%d" , &a, &c, &b);      switch  (c) {     case  '+' :         printf ("%d\n" , a + b);         break ;     case  '-' :         printf ("%d\n" , a - b);         break ;     case  '*' :         printf ("%d\n" , a * b);         break ;     default :         printf ("Input Error!\n" );     }     return  0 ; } 
3-5 旋转 (rotate) 题目: 输入一个 n*n 字符矩阵,把它左转 $90^\circ$ 后输出。
分析: 我做这道题时假定 n<1000 且不提前输入 n。所以,先读入第一行来判断 n 的大小。左转 $90^\circ$ 当然是通过变换下标来完成啦。具体怎么变嘛,画个图自己转一下就不难看出了。
解答: rotate.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #include  <stdio.h>  #include  <string.h>  #define  MAXN 1000 char  c[MAXN][MAXN]; int  main (void ) {     int  i, j, n;     memset (c, '\0' , sizeof (c));     fgets(c[0 ], MAXN, stdin );      n = strlen (c[0 ]) - 1 ;      for  (i = 1 ; i <= n-1 ; i++)          fgets(c[i], MAXN, stdin );     for  (i = n-1 ; i >= 0 ; i--) {          for  (j = 0 ; j < n; j++)             putchar (c[j][i]);         printf ("\n" );     }     return  0 ; } 
3-6 进制转换1 (base1) 题目: 输入基数 b $(2\leq b \leq 10)$ 和正整数 n (十进制),输出 n 的 b 进制表示。
分析: 模拟手动进制换算的过程,不断除以 b 求余,再逆序输出余数。为了实现余数逆序输出,可以在求出来的时候把它们存入数组里。
解答: base1.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include  <stdio.h>  #include  <string.h>  #define  MAXN 32 int  bn[MAXN];int  main (void ) {     int  b, n, i;     memset (bn, 0 , sizeof (bn));     scanf ("%d%d" , &b, &n);     for  (i = 0 ; n > 0 ; i++) {         bn[i] = n % b;         n /= b;     }     for  (i = MAXN-1 ; i >= 0 ; i--)          if (bn[i] != 0 )             break ;     for  (; i>= 0 ; i--)          putchar (bn[i] + '0' );     putchar ('\n' );     return  0 ; } 
3-7 进制转换2 (base2) 题目: 输入基数 b $(2\leq b \leq 10)$ 和正整数 n (b 进制),输出 n 的十进制表示。
分析: 这题 3-6 稍微更容易一些,因为不用考虑逆序输出。同样,也是模拟手算,只需手写一个例子,就可以搞清楚规则了,如:
题目: base2.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #include  <stdio.h>  int  main (void ) {     int  b, n, i, j, mi, sum = 0 ;     scanf ("%d%d" , &b, &n);     for  (i = 0 ; n > 0 ; i++) {         for  (j = 1 , mi = 1 ; j <= i; j++) mi *= b;         sum += (n % 10 ) * mi;         n /= 10 ;     }     printf ("%d\n" , sum);     return  0 ; } 
3-8 手机键盘 (keyboard) 题目: 输入一个由小写字母组成的英文单词,输出用手机的默认英文输入法的敲键序列。例如要打出 pig 这个单词,需要按 1 次 p,3 次 i,(稍作停顿后)1次 i,记为 p1i3i1。
分析: 我觉得题目的描述不太清楚,所以我理解的是:若输入 pig,则输出 p1i3g1。这样的话,就只需先输出一个字母然后输出它的对应数字即可。为了方便,我用常量表来做:
解答: keyboard.c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include  <stdio.h>  #include  <string.h>  int  keyboard[] = {    1 , 2 , 3 ,     1 , 2 , 3 ,     1 , 2 , 3 ,     1 , 2 , 3 ,     1 , 2 , 3 ,     1 , 2 , 3 , 4 ,     1 , 2 , 3 ,     1 , 2 , 3 , 4  }; #define  MAXN 100 char  word[MAXN];int  main (void ) {     int  n, i;     fgets(word, MAXN, stdin );     n = strlen (word) - 1 ;     for  (i = 0 ; i < n; i++)         printf ("%c%d" , word[i], keyboard[word[i]-'a' ]);      putchar ('\n' );     return  0 ; }