第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; }