第03章_数组和字符串

03_数组和字符串

Example_0301_逆序输出_数组.cpp

Example_0302_开灯问题.cpp

Example_0303_蛇形填数.cpp

Example_0304_竖式问题.cpp

Example_0305_最长回文子串_预处理方法.cpp

Exercise_0301_分数统计(stat)_vector_pair.cpp

Exercise_0302_单词的长度(word)_string.cpp

Exercise_0303_乘积的末3(product)_cctype.cpp

Exercise_0304_计算器(calculator)_simple.cpp

Exercise_0305_方阵旋转(rotate).cpp

Exercise_0306_进制转换1(base1)_十进制转x进制.cpp

Exercise_0307_进制转换2(base2)_x进制转十进制.cpp

Exercise_0308_手机键盘(keyboard).cpp

 

// Example_0301_逆序输出_数组.cpp

/**
 * 题目名称:逆序输出
 * 题目描述:将数组内的数逆序输出。
 **/

#include <stdio.h>
#define MAXN 100 + 10
                       // 为保险起见,这里将数组的最大值声明得稍大一些
int a[MAXN];           // 比较大的数组应尽量声明在main函数外
                       // 附: 全局变量在静态存储区分配内存
                       //      局部变量在栈上分配内存空间

int main()
{
    int i, x, n = 0;
    while(scanf("%d", &x) == 1){
        a[n++] = x;
    }
    for (i = n - 1; i >= 1; i--){
        printf("%d ", a[i]);
    }
    printf("%d\n", a[0]);
    return 0;
}


 

// Example_0302_开灯问题.cpp

/**
 * 题目名称:开灯问题
 * 题目描述:
 *      有n盏灯,编号为1~n。第1个人把所有灯打开,第2个人按下所有编号为2的总数的开关(这些灯将补关掉),
 * 第3个人按下所有编号为3的倍数的开关(其中关掉的灯将被打开,开着的灯将被关掉),依此类推。
 * 一共有k个人,问最后有哪此灯开着?输入n和k,输出开着的灯的编号。 k <= n <= 1000.
 * 样例输入: 7 7
 * 样例输出: 1 5 6 7
 **/

/**
 * 题目分析:
 *     这题并不难,只需要使用两个循环即可实现。
 * 首先,我们可以先去理解一下开关灯实际上是什么,可以知道,开关灯,实际上是一种状态。
 * 那么,我们可以使用一个数值来代表这种状态,下面的程序,用数值1表示开灯,数值0表示关灯。
 * 由于这里有1 ~ n 盏灯,我们可以用一个数组来存放这n盏灯的信息。
 * 解决开关灯状态问题后,可以开始算法思路:
 * 题目中,要求第n个人就会将编号为n的倍数的灯的状态值改变,那么,我们可以在一个循环中负责实现“人”的改变。
 * 然后,再在这个“人”的改变的循环中再嵌入一个处理”灯“的状态改变的函数。
 **/

#include <stdio.h>
#include <string.h>
#define MAXN 1000 + 10
int a[MAXN];

int main()
{
    int i, j, n, k, first = 1;
    memset(a, 0, sizeof(a));
    scanf("%d%d", &n, &k);
    for (i = 1; i <= k; i++){
        for (j = 1; j <= n; j++){
            if(j % i == 0){     // 无余数时是倍数关系,灯的状态得做出对应的变化
                a[j] = !a[j];
            }
        }
    }
    for ( i = i; i <= n; i++){
        if(a[i]){
            if (first){
                first  = 0;
            }
            else{
                printf(" ");
            }
            printf("%d", i);
        }
    }
    printf("\n");
    return 0;
}


 

// Example_0303_蛇形填数.cpp

/**
 * 题目名称:蛇形填数
 * 题目描述:在n*n方阵里填入1, 2, ..., n*n, (n <=8)要求填成蛇形(多余的空格只是为了便于观察规律,不必严格输出)。
 * 样例输入: 4
 * 样例输出:
 *             10 11 12 1
 *              9 16 13 2
 *              8 15 14 3
 *              7  6  5 4
 **/

/**
 * 题目分析:
 *     这里主要用到的是二维数组的知识,还有有点类似“迷宫”的一个判断方法。
 *     首先原题说需要n*n (n <= 8)的方阵,那么,我们只需要定义一个a[n][n]的数组即可。
 *     接下来,观察输出矩阵的蛇形规律,将数组中的每一元素初始化为0,将数字“1“从右上角开始填写,
 * 然后,一直沿着 下 -> 左 -> 上 -> 右 的方向填充数字,直到全部0都填完为止。
 * 那么,我们需要解决的问题,就只有如何能让它按这个方向走呢?我们可以将本来的0作为是否需要填充标记,
 * 再将数组的边界作为另一个是否越界的标记。总之,就是根据这些标记,沿着指定方向,填充到不能填充为止。
 * 最后,要解决的问题就是,如何知道它已经全部填充完了,然后跳出这个循环呢?我们可以用它本来需要填充的
 * 数字个数作为标记,当它的数值小于方阵的总格子个数时,即符合要求。当然,需要注意的一个问题就是,当进行
 * 确定它移动方向的判断时,需要先从数组边界作为越界条件去判断,然后再从数值上判断,这是为了防止内存溢出
 * 的情况出现。
 **/

#include <stdio.h>
#include <string.h>
#define MAXN 10

int a[MAXN][MAXN];

int main()
{
    int n, x, y, tot = 0;
    scanf("%d", &n);
    memset(a, 0, sizeof(a));
    tot = a[x = 0][y = n - 1] = 1;
    while(tot < n * n){
        while(x + 1 < n && !a[x + 1][y]) a[++x][y] = ++tot;     // 下
        while(y - 1 >= 0 && !a[x][y -1]) a[x][--y] = ++tot;     // 左
        while(x - 1 >= 0 && !a[x - 1][y]) a[--x][y] = ++tot;    // 上
        while(y + 1 < n && !a[x][y + 1]) a[x][++y] = ++tot;     // 右
    }
    for (x = 0; x < n; x++){        // 行输出
        for (y = 0; y < n; y++){    // 列输出
            printf("%3d", a[x][y]);
        }
        printf("\n");
    }
    return 0;
}


 

// Example_0304_竖式问题.cpp

/**
 * 题目名称:竖式问题
 * 题目描述:
 *      找出所有形如abc*de(三位数乘以两位数)的算式,使得在完整的竖式中,所有数字都属于一个特定的数字集合。
 * 输入数字集合(相邻数字之间没有空格),输出所有竖式。每个竖式前应有编号,之后应有一行空行。最后输出解的总数。
 * (为了便于观察,竖式中的空格改用小数点显示,但你的程序应该输出空格,而非小数点)。
 * 样例输入: 2357
 * 样例输出:
 * <1>
 * ..775
 * X..33
 * -----
 * .2325
 * 2325.
 * -----
 * 25575
 *
 * The number of solutions = 1
 **/

 /**
  * 题目分析:
  * 尝试所有的abc和de,判断是否满足条件 if (" abc *de")是个合法的竖式)打印abc*de的竖式和其后的空行。
  * 其实主要还是要找出主要需要解决的条件,在这题里面,需要解决的问题主要有两个。
  * 第一个:输出格式控制,这个主要对cout或者prinf的使用方法熟悉即可,
  * 第二个:“所有数字都属于一个特定的数字集合”,这里需要掌握筛选数字的技巧,下例中使用了“缓冲区”的方法。
  *          首先,申请两个字符数组,第一个字符数组用于存放用户输入的字符,第二个字符数组用于存放进行乘法时出现过的数字的保存。
  *          开始执行的过程,
  *          第一步,将用户输入数字集合放到s字符组中。
  *          第二步,计算,然后将计算时所有出现过的数字存放到另一个字符数组buf中。
  *          第三步,开始逐个比较,判断是否buf中每个字符都能从s字符组中找到,起到了最终的筛选作用。
  **/

  #include <stdio.h>
  #include <string.h>

  int main()
  {
      int i, ok, abc, de, x, y, z, count = 0;
      char s[20], buf[99];
      scanf("%s", s);           // 要求用户输入数字集合,并将数字集合放入到字符组s[20]中。
      for (abc = 111; abc <= 999; abc++){ // 这两个循环是为了列举所有的两位数和三位数的数字集合
          for (de = 11; de < 99; de++){
              x = abc * (de % 10);
              y = abc * (de / 10);
              z = abc * de;
              sprintf(buf, "%d%d%d%d%d", abc, de, x, y, z); // 将计算结果得出的数字全部放入到buf字符组中
              ok = 1;
              for(i = 0; i < strlen(buf); i++){
                  if (strchr(s, buf[i]) == NULL){  // 测试buf字符组中的每一个字符是否都能从s字符组中找出
                      ok = 0;
                  }
              }
              if(ok){
                  printf("<%d>\n", ++count);
                  printf("%5d\nX%4d\n-----\n%5d\n%4d\n-----\n%5d\n\n", abc, de, x, y, z);
              }
          }
      }
      printf("The number of solutions = %d\n", count);
      return 0;
  }

// 补充: #include <stdio.h>  int sprintf( char *buffer, const char *format, ... );
// sprintf()函数和printf()类似, 只是把输出发送到buffer(缓冲区)中.返回值是写入的字符数量.

// 补充: #include <string.h>  char *strchr( const char *str, int ch );
// 功能:函数返回一个指向str 中ch 首次出现的位置,当没有在str 中找ch到返回NULL。
// 在C++里面可以用#include <cstring>  size_type find( char ch, size_type index );




 

// Example_0305_最长回文子串_预处理方法.cpp

/**
 * 题目名称:最长回文子串
 * 题目描述:
 *      输入一个字符串,求出其中最长的回文子串。子串的含义是:在原串中连续出现的字符串片段。
 * 回文的含义是:正着看和倒着看相同,如abba和yyxyy。在判断时,应该忽略所有标点符号和空格,
 * 且忽略大小写,但输出应保持原样(在回文串的首部和尾部不要输出多余字符)。输入的字符串长度
 * 不超过5000,且占据单独一行。应该输出最长的回文串,如果有多个,输出起始位置最靠左的。
 * 样例输入: Confuciuss say: Madam, I'm Adam.
 * 样例输出: Madam, I'm Adam.
 **/

 /**
  * 温馨提示:
  * 1. 使用fgetc(fin)可以从打开的文件fin中读取一个字符。
  * 2. 不同操作系统的回车换行符是不一致的。
  *     Windows是'\r'和'\n'两个字符,Linux是'\n',而MacOS是'r'.
  * 3. fgets(buf, MAXN, fin)读取完整的一行,
  *     (相当于C++里面的 istream &getline( char *buffer, streamsize num, char delim );)
  **/

  /**
   * 题目分析:
   * 下面程序的主要思路概括:
   * 1. 预处理,提取转换所有的字符串。
   * 2. 遍历,设区间,比较,设标记。
   * 3. 得出结果,还原输出。
   *
   * 1. 关于预处理,下面通过了使用isalpha判断是否字母,如是字母则将原字符转换为小写放入新字符串。
   *    在放入时,还另外使用了一个数组p,用以保存预处理后的字符在原字符串中的位置,方便还原。
   * 2. 关于如何遍历比较,这里使用了循环变量i作为中心,然后再设一循环j,作为两边散开的点,作为比较点。
   *    如:现在由i做中心,长度区间为 j - i 至 j + 1;   那么,在比较时,就会 j - i 与 j + i 比较,
   *        j不断减小,如果到最后它们也不跳出循环,就使用max,x, y保存现在的位置,暂作为符合条件的最长子字符串。
   *    刚刚所说的是j - i 和j + i 这是在考虑子串长度为奇数的时候所使用的,它会以i为中心向两边散开, j 0 0 i 0 0 j
   *    当其为偶数的时候, 需要以i中左偏中心,然后,再向两边散开比较, 如: j - i 至j + i + 1 ,理解为: j 0 i 0 0 j
   * 3. 几个比较重要的变量 max : 保存最大子串的长度, p[m],本身下标为对应的预处理后的下标,值为原串的下标。
   **/

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAXN 5000 + 10

char buf[MAXN], s[MAXN];
int p[MAXN];

int main()
{
    // 初始化
    int n, m = 0, max = 0, x, y;
    int i, j;
    fgets(buf, sizeof(s), stdin);
    n = strlen(buf);

    // 预处理(字符串转换)
    for (i = 0; i < n; i++){
        if(isalpha(buf[i])){
            p[m] = i;
            s[m++] = toupper(buf[i]);
        }
    }

    // 数据判断(判断是否回文串)
    for( i = 0; i < m; i++){
        for (j = 0; i - j >= 0 && i + j < m; j++){ // 这里是为了比较总长度为奇数的子字符串
            if (s[i - j] != s[i + j]){
                break;
            }
            if (j * 2 + 1 > max) {
                max = j * 2 + 1;
                x = p[i - j];
                y = p[i + j];
            }
        }
        for (j = 0; i - j >= 0 && i + j + 1 < m; j++){// 这里是为了比较总长度为偶数的子字符串
            if (s[i - j] != s[i + j + 1]){
                break;
            }
            if (j * 2 + 2 > max){
                max = j * 2 + 2;
                x = p[i - j];
                y = p[i + j + 1];
            }
        }
    }

    // 结果输出
    for ( i = x; i <= y; i++){
        printf("%c", buf[i]);
    }
    printf("\n");
    return 0;
}

/**
 * 模拟输出过程:
 * Confuciuss say: Madam, I'm Adam.
 *
 * i = 0     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 0 i + j = 0 m = 24
 * 第一个for的max 1 然后用x 与 y 保存 i - j与i+j的值
 *
 * 第二个for: j = 0 i - j = 0 i + j + 1 = 1 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 1     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 1 i + j = 1 m = 24
 * 第一个for: j = 1 i - j = 0 i + j = 2 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 1 i + j + 1 = 2 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 2     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 2 i + j = 2 m = 24
 * 第一个for: j = 1 i - j = 1 i + j = 3 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 2 i + j + 1 = 3 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 3     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 3 i + j = 3 m = 24
 * 第一个for: j = 1 i - j = 2 i + j = 4 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 3 i + j + 1 = 4 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 4     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 4 i + j = 4 m = 24
 * 第一个for: j = 1 i - j = 3 i + j = 5 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 4 i + j + 1 = 5 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 5     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 5 i + j = 5 m = 24
 * 第一个for: j = 1 i - j = 4 i + j = 6 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 5 i + j + 1 = 6 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 6     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 6 i + j = 6 m = 24
 * 第一个for: j = 1 i - j = 5 i + j = 7 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 6 i + j + 1 = 7 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 7     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 7 i + j = 7 m = 24
 * 第一个for: j = 1 i - j = 6 i + j = 8 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 7 i + j + 1 = 8 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 8     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 8 i + j = 8 m = 24
 * 第一个for: j = 1 i - j = 7 i + j = 9 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 8 i + j + 1 = 9 m = 24
 * 第二个for的max 2 然后用x 与 y 保存 i - j与i+j+1的值
 * 第二个for: j = 1 i - j = 7 i + j + 1 = 10 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 9     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 9 i + j = 9 m = 24
 * 第一个for: j = 1 i - j = 8 i + j = 10 m = 24
 * 第一个for的max 3 然后用x 与 y 保存 i - j与i+j的值
 * 第一个for: j = 2 i - j = 7 i + j = 11 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 9 i + j + 1 = 10 m = 24
 * 第二个for: j = 1 i - j = 8 i + j + 1 = 11 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 10     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 10 i + j = 10 m = 24
 * 第一个for: j = 1 i - j = 9 i + j = 11 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 10 i + j + 1 = 11 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 11     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 11 i + j = 11 m = 24
 * 第一个for: j = 1 i - j = 10 i + j = 12 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 11 i + j + 1 = 12 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 12     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 12 i + j = 12 m = 24
 * 第一个for: j = 1 i - j = 11 i + j = 13 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 12 i + j + 1 = 13 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 13     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 13 i + j = 13 m = 24
 * 第一个for: j = 1 i - j = 12 i + j = 14 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 13 i + j + 1 = 14 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 14     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 14 i + j = 14 m = 24
 * 第一个for: j = 1 i - j = 13 i + j = 15 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 14 i + j + 1 = 15 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 15     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 15 i + j = 15 m = 24
 * 第一个for: j = 1 i - j = 14 i + j = 16 m = 24
 * 第一个for: j = 2 i - j = 13 i + j = 17 m = 24
 * 第一个for的max 5 然后用x 与 y 保存 i - j与i+j的值
 * 第一个for: j = 3 i - j = 12 i + j = 18 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 15 i + j + 1 = 16 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 16     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 16 i + j = 16 m = 24
 * 第一个for: j = 1 i - j = 15 i + j = 17 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 16 i + j + 1 = 17 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 17     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 17 i + j = 17 m = 24
 * 第一个for: j = 1 i - j = 16 i + j = 18 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 17 i + j + 1 = 18 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 18     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 18 i + j = 18 m = 24
 * 第一个for: j = 1 i - j = 17 i + j = 19 m = 24
 * 第一个for: j = 2 i - j = 16 i + j = 20 m = 24
 * 第一个for: j = 3 i - j = 15 i + j = 21 m = 24
 * 第一个for的max 7 然后用x 与 y 保存 i - j与i+j的值
 * 第一个for: j = 4 i - j = 14 i + j = 22 m = 24
 * 第一个for的max 9 然后用x 与 y 保存 i - j与i+j的值
 * 第一个for: j = 5 i - j = 13 i + j = 23 m = 24
 * 第一个for的max 11 然后用x 与 y 保存 i - j与i+j的值
 *
 * 第二个for: j = 0 i - j = 18 i + j + 1 = 19 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 19     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 19 i + j = 19 m = 24
 * 第一个for: j = 1 i - j = 18 i + j = 20 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 19 i + j + 1 = 20 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 20     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 20 i + j = 20 m = 24
 * 第一个for: j = 1 i - j = 19 i + j = 21 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 20 i + j + 1 = 21 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 21     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 21 i + j = 21 m = 24
 * 第一个for: j = 1 i - j = 20 i + j = 22 m = 24
 * 第一个for: j = 2 i - j = 19 i + j = 23 m = 24

 * 第二个for: j = 0 i - j = 21 i + j + 1 = 22 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 22     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 22 i + j = 22 m = 24
 * 第一个for: j = 1 i - j = 21 i + j = 23 m = 24
 * 第一个for比较出i-j与i+j的字符不同,break出循环。
 *
 * 第二个for: j = 0 i - j = 22 i + j + 1 = 23 m = 24
 * 第二个for比较出i-j与i+j+1的字符不同,break出循环。
 *
 * i = 23     下面开始进行新一轮
 *
 * 第一个for: j = 0 i - j = 23 i + j = 23 m = 24
 *
 * 结果: Madam, I'm Adam
 * 请按任意键继续. . .
 **/


 

// Exercise_0301_分数统计(stat)_vector_pair.cpp

/**
 * 题目名称:分数统计(stat)
 * 题目描述:
 *      输入一些学生的分数,哪个分数出现的次数最多?如果有多个并,从小到大输出。
 * 分数均为不超过100的非负实数,但最多保留两位小数。
 * 样例输入:11 11 12 12 13 13 14 14 15 16 18 39 a
 * 样例输出:11.00 分数出现了 2 次。
 * 12.00 分数出现了 2 次。
 * 13.00 分数出现了 2 次。
 * 14.00 分数出现了 2 次。
 * 请按任意键继续. . .
 **/

/**
 * 题目分析:
 *
 * 需要进行的操作及需要满足的条件:
 * 1. 输入不确定学生数目的分数
 * 2. 找出相同分数出现的最多次数。
 * 3. 如有重复的最多次数,将其从小到大输出。
 * 4. 输出时进行格式控制,最多保留两位小数。
 *
 * 程序主要思路:
 * 1. 初始化与输入,输入到unsignedDoubleGroup中
 * 2. 获取在double向量组中每个成员出现的次数将其放入maxNumber向量组中.
 * 3. 找出分数出现次数的最大值
 * 4. 查找拥有相同最大值的数据有哪些,并将这些全部保存入result向量组中
 * 5. 输出result向量组中的结果.
 *
 * 思路再分析:
 * 1. 为了满足条件1,我们可以直接使用一个while(cin >> double)的方式来输入保存数据,将数据保存至vector中,
 *    因为需要多次重复使用这些数据,而且不知道数据的数量,所以就选择了vector。
 * 2. 获取每个成员出现次数的方法,可以先将这个vector中的数据提取出来,然后对该数组内的数逐个比较。
 * 3. 找出一组数中哪个是最大值,可直接遍历一次向量组。
 * 4. 为了判断是否有相同最大值的数据,我们还是需要遍历一次向量组,在找出有相同的最值时,这个最值对应的
 *    向量组中的这个元素放到新建的一个result向量组中保存结果。
 * 5. 遍历输出这个result向量组的结果。
 *
 **/

#include <iostream>
#include <vector>
#include <utility>

using std::cin;
using std::cout;
using std::endl;
using std::ios_base;

int main()
{
    // 1. 初始化与输入,输入到unsignedDoubleGroup中
    std::vector<double> unsignedDoubleGroup;
    double unsignedDouble = -1.0;
    while(cin >> unsignedDouble){
        unsignedDoubleGroup.push_back(unsignedDouble);
    }
    if (-1.0 == unsignedDouble){    // 当一个数值也没有输入的时候可以直接跳出该函数
        return 0;
    }

    // 2. 获取在double向量组中每个成员出现的次数将其放入maxNumber向量组中.
    int groupLong = unsignedDoubleGroup.size();
    std::vector<int> maxNumber(groupLong, 0);    // 长度为groupLong,初值全为0的整型向量组,记录每个数字出现的次数
    for (int i = 0; i < groupLong; ++i){
        const double testInt = unsignedDoubleGroup[i];
        for (int j = 0; j < groupLong; ++j){
            if (testInt == unsignedDoubleGroup[j]){
                maxNumber[i]++;                 // 出现次数相加
            }
        }
    }

    // 3. 找出分数出现次数的最大值
    int maxOne = maxNumber[0];
    for ( int i = 0; i < groupLong; ++i){
        if (maxNumber[i] > maxOne){
            maxOne = maxNumber[i];
            }
    }

    // 4. 查找拥有相同最大值的数据有哪些,并将这些全部保存入result向量组中
    std::pair<int, double> tempPair;
    std::vector< std::pair<int, double> > result;
    for (int i = 0; i < groupLong; ++i){
        if (maxNumber[i] == maxOne){
            bool haveSame(false);
            for ( int j = 0; j < int(result.size()); ++j){
                if (result[j].second == unsignedDoubleGroup[i]){
                    haveSame = true;
                    break;
                }
            }
            if (false == haveSame){
                tempPair.first = maxOne;
                tempPair.second = unsignedDoubleGroup[i];
                result.push_back(tempPair);
            }
        }
    }

    // 5. 输出result向量组中的结果
    cout.precision(2);
    cout.setf(ios_base::fixed, ios_base::floatfield);
    for (int i = 0; i < int(result.size()); ++i){
        cout << result[i].second << " 分数出现了 " << result[i].first << " 次。" << endl;
    }

	system("pause");
    return 0;
}


 

// Exercise_0302_单词的长度(word)_string.cpp

/**
 * 题目名称:单词的长度(word)
 * 题目描述:输入若干个单词,输出它们的平均长度。单词只包含大写字母和小写字母。
 **/

#include <cstring>
#include <iostream>

using namespace std;

int main()
{
    string word;
    long sum = 0;
    long count = 0;
    while (!cin.eof() && cin >> word){
        ++count;
        sum += word.size();
    }
    cout << sum / count << endl;
    return 0;
}


 

// Exercise_0303_乘积的末3位(product)_cctype.cpp

/**
 * 题目名称:乘积的末3位(product)
 * 题目描述:
 *      输入若干个整数(可以是正数、负数或者零),输出它们的乘积的末3位。
 * 这些整数中会混入一些由大写字母组成的字符串,你的程序中应当忽略它们。
 * 样例输入:+1 +2 + -1 -2 k 12 english 54 9876 -111
 * 样例输出:712
 **/

/**
 * 题目分析:
 *     题目难度主要在于参差的数据类型输入。
 * 题目总思路,使用while语句逐个string作为单词输入。
 * 然后通过调用函数bool getInt(...)判断该单词是否整数,另外,再利用该函数的形参将正确的整数返回。
 * 将从函数里面得出的整数与结果相乘,乘后保留末三位整数即可。
 * 其中,关于如何实现bool getInt(string get, int & nowGet)才是难题。实现方法如下:
 * 首先,考虑不是整数的情况,1.字符串为空,返回false, 2.是字母或是仅有一个符号。
 * 除了字符串为空的情况外,我们可以开始考虑字符串不为空的情况,字符串不为空时,存在三种情况,
 * 第一种,带符号的整数,第二种,不带符号的整数,第三种,不是整数。
 * 关于这三种情况,可以使用一个if-else if- else语句来实现,
 * 第一种情况:if ('+' == get[0] || '-' == get[0])带上了符号,可以直接忽略读取第[0]位符号位,然后再
 *               从最尾位开始读取,读取3位数即可停止,当读取途中不满三位数或者碰上符号位时,
 *               立即返回。
 * 第二种情况:if('0' <= get[0] && '9' >= get[0]) 直接是数字的情况下,跟第一种情况的思路基本一致,
 *               直接从最尾位开始取个位数,次尾位取十位数,倒数第三位取百位数。
 * 第三种情况:由于不符合需要的整数的转换条件,只需要直接返回false即可.
 * 另外,如果想将字符型的数字转换成数值,只需要将原来的字符型减去'0'即可得到相对应的数值。
 **/

#include <cstring>
#include <string>
#include <cctype>
#include <cmath>
#include <iostream>

using namespace std;


bool getInt(string get, int & nowGet)
{
	int stringLong = get.length();
	if (0 == stringLong){
		return false;
	}
	nowGet = 0;
	if ('+' == get[0] || '-' == get[0]){ // 带符号的正数或负数
		if (0 == (stringLong - 1)){ // 它只包含了一个符号,则直接返回
			return false;
		}
		for (int j = 0, i = stringLong - 1; i > 0 && i >= stringLong - 3; --i, ++j){
			if ('+' == get[i] || '-' == get[i]){	// 正在循环转换的过程,这个数字不满三位数,遇上了符号,直接跳出
				break;
			}
			nowGet += int(get[i] - '0') * (int) (pow(double(10), j));
		}
		return true;
	}
	else if('0' <= get[0] && '9' >= get[0]){ // 直接是数字的情况下
		for (int j = 0, i = stringLong - 1; i >= 0 && i >= stringLong - 3; --i, ++j){
			nowGet += int(get[i] - '0') * (int) (pow(double(10), j));
		}
		return true;
	}
	else{	// 是字母
		return false;
	}
}

int main()
{
    string word;
    long result = 1;
    while(cin >> word){
		int temp;
		if (getInt(word, temp))
		{
			result = (result * temp) % 1000;
		}
    }
	cout << result << endl;
    return 0;
}


 

// Exercise_0304_计算器(calculator)_simple.cpp

/**
 * 题目名称:计算器
 * 题目描述:
 *      编写程序,读入一行恰好包含一个加号、减号或乘号的表达式,输出它的值。
 * 这个运算符保证是二元运算符,且两个运算符均不超过100的非负整数。
 * 运算符和运算符可以紧挨着,也可以用一个或多个空格、TAB隔开。行首末尾均可以有空格。
 * 样例输入: 1+1
 * 样例输出: 2
 * 样例输入: 2- 5
 * 样例输出: -3
 * 样例输入: 0 *1982
 * 样例输出: 0
 **/

#include <iostream>

using namespace std;

int main()
{
    int a, b;
    char oper;
    cin >> a;
    do{
        cin.get(oper);          // 这题只要灵活运用 istream &get( char &ch );
    }while(!('+' == oper || '-' == oper  || '*' == oper) );
    cin >> b;
    if('+' == oper){
        cout << a + b << endl;
    }
    else if('-' == oper){
        cout << a - b << endl;
    }
    else{  // *
        cout << a * b << endl;
    }
    return 0;
}


 

// Exercise_0305_方阵旋转(rotate).cpp

/**
 * 题目名称:矩阵旋转(rotate)
 * 题目描述:输入一个n*n字符矩阵,把它左转90度后输出。
 * 样例输入:
 *     1     2     3     4
 *     5     6     7     8
 *     9    10    11    12
 *     13    14    15    16
 * 样例输出:
 *     4     8    12    16
 *     3     7    11    15
 *     2     6    10    14
 *     1     5     9    13
 **/

 /**
  * 题目分析:
  *     这题其实很简单,刚刚开始我还在苦想呢,它究竟左旋时下标间有些什么规律呢?
  * 后来看着看着才发觉,原来啊,只需要将输入输出的顺序调转一下即可,
  * 输入时,按横,列坐标的方式输入;输出时,按先列后横坐标的方式逐列输出。
  * 输入时,i = 0, j = 1, 2, 3....  输出时, j = 3, i = 0, 1, 2...
  * 至于如何知道它是一个多少阶的矩阵,可以使用开方的方法求得。
  **/

#include <queue>
#include <vector>
#include <cmath>
#include <iostream>

using namespace std;

int main()
{
	// 初始化,输入队列,保存元素
    queue<int> allInOne;
    int tempOne;
    while(cin >> tempOne){
        allInOne.push(tempOne);
    }
    double count = allInOne.size();
    int n = int(sqrt(count));

	// 提取并保存元素
    vector<int> init;
    vector< vector<int> > outit;
    for (int i = 0; i < n; ++i){
        for(int j = 0; j < n; ++j){
        init.push_back(allInOne.front());
        allInOne.pop();
        }
        outit.push_back(init);
        init.clear();
    }

	// 按一定顺序输出元素
    for (int j = n - 1; j >= 0; --j){
        for (int i = 0; i < n; ++i){
            cout << outit[i][j] << " ";
        }
        cout << endl;
    }
    return 0;
}



 

// Exercise_0306_进制转换1(base1)_十进制转x进制.cpp

/**
 * 题目名称:进制转换(base1)
 * 题目描述:输入基数b(2 <= b <= 10)和正整数n(十进制),输出n的b进制表示。
 **/

 /**
  * 题目分析:
  * 1. 用户输入十进制数值n,基数b。
  * 2. 要求,转换为由基数b的数字。
  * 3. 这里,可以将这最终结果的数字拆分出来,将一个数字,变为一位数就一个数字,最后遍历输出。
  * 4. 假设输入数值为10,基数为3,结果应为201,我们可以试试用加法的思想去想如何转化。
  * 5. 就像以前使用的算盘那样,数值每增大1,就在个位数上加1,当个位数上的1达到基数大小时,需要进位。
  * 6. 进位以后,需要将原数位清零,这较高位加1,然后,再继续判断这较高位是否可以进位,如此循环。
  * 7. 那么,意思是: ++数值 -> 最代位(原数位)++ -> 判断是否达到基数大小 -> 原数位清零 -> 较高位++...
  * 8. 可以看出,除了第一步的操作外,下面的操作已经开始进入循环体了,也就是说,我们需要解决的第一个问题是:
  *    确定要加多少次数值。 这里,只需要将用户输入的数值n做这样的操作即可:while(n--){}
  *    在上面的循环体中,该放些什么呢?循环体中,已经开始数值相加了,也就是说,需要先初始化一个带个位数的东西,
  *    下面程序选择了vector向量 vector <int> save(1, 0),初始化1个元素,值为0,循环体中,还需要一个用来确认位数
  *    的变量,申请int变量int weishu,刚刚开始时第0位,然后,进行位数上的数值递增操作,判断是否与基数相等,
  *    若不相等,则可以继续下一步的相加操作,若相等,则需要先将现在在进行操作的数组清零,然后,再将位数移到下一位,
  *   因为不知道下一位是否已经在vector里面申请了空间,所以,这里需要先做一个weishu与vector数组长度比较,以防止内存
  *    溢出,接下来只需要进入循环不断地判断是否执行进行操作就可以了。
  * 9. 在跳出了while(n--){]后,就意味着数值转换操作全部完毕,然后,只需要按顺序输出刚刚保存的向量就可以了。
  **/

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int n, b;
    cin >> n >> b;
    vector <int> save(1, 0); // 初始化1个元素,值为0
    while(n--){
        int weishu = 0;
        while(b == ++save[weishu]){ // 此处进行加1的操作,然后判断是否能进位
            save[weishu] = 0;    // 清零进一
            ++weishu;
            if(save.size() < weishu + 1){    // 考虑进一时是否会越界
                save.push_back(0);
            }
        }
    }

    for (int i = save.size() - 1; i >= 0; --i){
        cout << save[i];
    }
    cout << endl;

    return 0;
}


 

// Exercise_0307_进制转换2(base2)_x进制转十进制.cpp

/**
 * 题目名称:进制转换2(base2)
 * 题目描述:输入基数b(2 <= b <= 10)和正整数n(b进制),输出n的十进制表示。
 **/

 /**
  * 题目分析:
  * 1. 这题与上一题题目条件与结果刚刚相反,不过难度却增大了不少。
  * 2. 上一题是十进制转二进制,是已知十进制总数值大小的情况,相当于将数值逐个相加,可以使用进位的方法。
  * 3. 这一题是未知总数值大小,求十进制表示的总数值大小,将b进制的那个数,从最低位开始相减,为零则借位,直到全部位数为零。
  * 4. 这题关键点在于如何找到结束循环的条件,什么时候是借位结束,下面是部分的伪代码:
  *    while(未为全零){ // 这里循环刚刚开始时,可以先设一个bool值,用来标记这个数并非全为零,具体是否真为全零,可在循环中判断。
  *    if(检查到最低位为零){
  *                          bool notAllZero = false; // 非全零标记
  *                          if(这个数值的全部位数都为零){ notAllZero = true;} // 这里的判断方法可以通过遍历每一位数来实现
  *                          else{ notAllZero = false;}
  *                          while(正在操作的位数 == 0){
  *                                将这位数设为最大值; // 这里因为借位,如10-1的时候,本为0的那一位,变成了9
  *                                位数借一位;		   // 将操作的位数借一位
  *                                if(刚刚所借的这一位数 == 0)
  *                                   { continue; 继续这一个循环;} // 因为之前做过判全零的操作,所以这里不用担心会有溢出的情况发生
  *                                else
  *                                   {这一位数数值-1; break;} // 数值正常减1后,借位成功,可以break出循环体
  *                         }
  *    else { 本位数值-1; }   // 最低位不为零时,操作非常简单,将这最低位的数值减1即可.
  *    ++result; // 这是用来记录十进制的总值的,每当成功完成一次减值操作,就可以将十进制这边的数值加1了。相当于将总数值转移到另一变量上保存。
  *    }
  * 5. 要完成刚刚那伪代码,可以知道,只需要初始化几个变量就可以了,表示位数的变量,表示全零的标记...具体实现方法请看代码。
  **/

#include <iostream>
#include <cstring>
#include <string>

using namespace std;

int main()
{
    int b;
	string n;
    cin >> b >> n;
    int result(0);

	const long weishuMaxIndex = n.length() - 1;	// 最大下标代表最低位的数值
	bool notAllZero(true);
	while(notAllZero){
		int weishu = weishuMaxIndex;
		if ('0' == n[weishu]){
		// 判断是否全零,然后结束循环
			notAllZero = false;
			for(int i = weishuMaxIndex; i >= 0; --i){	// 判全零
				if ('0' != n[i]){
					notAllZero = true;
					break;
				}
			}
			if (false == notAllZero){		// 全部为零时,可直接结束循环
				break;
			}
			while('0' == n[weishu]){		// 正在操作的位数上数值为零
				n[weishu] = b + '0' - 1;	// 本位数上的数值设为最大
				weishu = weishu - 1;		// 借一位,然后再开始判断操作
				if ('0' == n[weishu]){		// 还是为零的话,继续循环操作
					continue;
				}
				else{						// 否则,可以数值减一,跳出循环,继续总体的下一步操作
					n[weishu] = n[weishu] - 1;
					break;
				}
			}
		}
		else{
			n[weishu] = n[weishu] - 1;
		}
		++result;
	}
	cout << result << endl;

	system("pause");
    return 0;
}



 

// Exercise_0308_手机键盘(keyboard).cpp

/**
 * 题目名称:手机键盘(keyboard)
 * 题目描述:输入一个由小写字母组成的英文单词,输出用手机的默认英文输入法的敲键序列。
 * 样例输入:pig
 * 样例输出: p1i3i1
 **/

 /**
  * 题目分析:
  * 题目条件有4: 1. 九宫格 2. 用户输入英文单词 3. 根据九宫格输出按键顺序 4. 当按键前后相同时,需要输出同一字母
  * 首先,了解手机键盘上的九宫格是: (数字)1:(内容)空, 2:abc, 3:def, 4:ghi, 5:jkl, 6:mno, 7:pqrs, 8:tuv, 9:wxyz
  * 然后,要求用户输入一个单词。
  * 接着,输出这个按键序列,只需要使用一个switch语句判断每个字母需要在键盘上按键的数目,保存这个数目即可,另外再与现在的单词同步输出。
  * 最后,因为它还有一个条件需要去判断按键前后是否相同,我们可以再申请两个变量,用以保存前后两次的按键,再进行判断输出。
  * 另外,下面程序将preChar与nowChar初始化为不同的是为了防止第一次比较时会出现溢出,当它们相同的时候,会输出上一个字符,而首次输出时并不存在上一个字符之说。
  **/

#include <iostream>
#include <cstring>
#include <string>

using namespace std;

int main()
{
    string word;
	cin >> word;
	long wordLongMax = word.length();

	for(int wordLong = 0, preChar = 1, nowChar = 0; wordLong < wordLongMax; ++wordLong){
		int count = 0;
		switch(word[wordLong]){
			// 键盘上的数字2
			case 'a':	count = 1; nowChar = 2; break;
			case 'b':   count = 2; nowChar = 2; break;
			case 'c':   count = 3; nowChar = 2; break;
			// 键盘上的数字3
			case 'd':	count = 1; nowChar = 3; break;
			case 'e':   count = 2; nowChar = 3; break;
			case 'f':   count = 3; nowChar = 3; break;
			// 键盘上的数字4
			case 'g':	count = 1; nowChar = 4;  break;
			case 'h':	count = 2; nowChar = 4;  break;
			case 'i':	count = 3; nowChar = 4;  break;
			// 键盘上的数字5
			case 'j':	count = 1; nowChar = 5;  break;
			case 'k':	count = 2; nowChar = 5;  break;
			case 'l':	count = 3; nowChar = 5;  break;
			// 键盘上的数字6
			case 'm':	count = 1; nowChar = 6;  break;
			case 'n':	count = 2; nowChar = 6;  break;
			case 'o':	count = 3; nowChar = 6;  break;
			// 键盘上的数字7
			case 'p':	count = 1; nowChar = 7;  break;
			case 'q':	count = 2; nowChar = 7;  break;
			case 'r':	count = 3; nowChar = 7;  break;
			case 's':	count = 1; nowChar = 7;  break;
			// 键盘上的数字8
			case 't':	count = 1; nowChar = 8;  break;
			case 'u':	count = 2; nowChar = 8;  break;
			case 'v':	count = 3; nowChar = 8;  break;
			// 键盘上的数字9
			case 'w':	count = 1; nowChar = 9;  break;
			case 'x':	count = 2; nowChar = 9;  break;
			case 'y':	count = 3; nowChar = 9;  break;
			case 'z':	count = 1; nowChar = 9;  break;

			default:  exit(1);
		}
		if (preChar == nowChar){
			cout << word[wordLong - 1] << count;
		}
		else{
			cout << word[wordLong] << count;
		}
		preChar = nowChar;     // 记录这次的字符是在哪一个区域,方便下次做“是否相同键”的判断
	}
	cout << endl;
    return 0;
}



 

你可能感兴趣的:(第03章_数组和字符串)