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