【趣学C语言和数据结构100例】
问题描述
1.输入两个正整数 m 和 n,求其最大公约数和最小公倍数
2.输入一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数
3.求 Sn = a + aa + aaa + … + a…a 之值,其中 a 是一个数字,n 表示 a 的位数,n、a 由键盘输入。例如: 2 + 22 + 222 + 2222 + 22222(此时 n=5)
4.求 1! + 2! + 3! + 4! + … + 20!
(扩展)输入一个 n,求 n 的双阶乘,例如输入 20,求 2! + 4! + … + 18! + 20!
5.求 2/1 + 3/2 + 5/3 + 8/5 + … 前 20 项
代码分析
最大公约数和最小公倍数
最大公约数(GCD)的解法
辗转相除法(也称欧几里得算法):直接从 m 和 n 中较小的数开始递减,直到找到能同时整除 m 和 n 的最大数
最小公倍数(LCM)的解法
(1)普通解法:使用公式 LCM = (m * n) / 最大公约数 来计算。
(2)暴力解法:通过不断增加 y 的值,直到 y 能同时被 m 和 n 整除。效率较低。输入一行字符,统计个数
定义数组str存储输入的字符串,定义四个整型变量,用来计数。初始值都设为0。
使用fgets函数从标准输入(stdin)读取一行字符,存储到str数组中。
(fgets函数用法:fgets(str, 100, stdin))
for循环遍历
(1)使用函数:isalpha函数检查是否为英文字母,isspace函数检查是否为空格,isdigit函数检查是否为数字。
(2)使用==: str[i] = =’ '等。求 Sn = a + aa + aaa + … + a…a 之值,其中 a 是一个数字,n 表示 a 的位数,n、a 由键盘输入。例如: 2 + 22 + 222 + 2222 + 22222(此时 n=5)
找规律:输入n和a,定义pre_num和num用来表示当前aaa和 a + aa + aaa,for循环即可,循环次数为n,使用pre_num += a * pow(10, i);。求 1! + 2! + 3! + 4! + … + 20!
找规律:关于阶乘,考虑数值过大,使用long long定义变量,factorial和sum用来表示当前3! 和 1! + 2! + 3!。
//求阶乘使用
for (j = 1; j <= i; j++) {
factorial *= j;
}
(扩展)输入一个 n,求 n 的双阶乘,例如输入 20,求 2! + 4! + … + 18! + 20!
突然想到可以扩展题求n 的双阶乘,思路同上。
- 求 2/1 + 3/2 + 5/3 + 8/5 + … 前 20 项
找规律:可发现,后一个的分子为前一个的分子+分母,后一个的分子为前一个的分子,定义sum为和,for循环求,每次吧前一个的分子给temp保管,分别赋值。
通义灵码思路重构
通义灵码思路如下:
求最大公约数和最小公倍数
问题:当前实现中,求最大公约数的方法效率较低,可以使用更高效的欧几里得算法。
改进:
使用 gcd 函数来计算最大公约数。
最小公倍数可以通过公式 lcm = (m * n) / gcd 计算。统计字符类型
问题:当前实现中,fgets 读取输入后,scanf 可能会读取到多余的字符。
改进:
使用 getchar() 清除输入缓冲区中的多余字符。求 Sn = a + aa + aaa + … + a…a 之值
问题:当前实现中,使用 pow 函数可能导致精度问题。
改进:
使用整数运算直接构建每个项。求 1! + 2! + 3! + 4! + … + 20!
问题:当前实现中,每次计算阶乘时都重新从 1 开始计算,效率较低。
改进:
使用累积的方式计算阶乘,避免重复计算。求 2/1 + 3/2 + 5/3 + 8/5 + ... 前 20 项
问题:当前实现中,sum 变量在循环中被覆盖,导致最终结果不正确。
改进:
使用单独的变量累加每项的结果。
代码实现
#include <stdio.h>
#include <cstring>
#include <ctype.h>
#include <math.h>
int main() {
// 1.输人两个正整数 m 和 n,求其最大公约数和最小公倍数
int m, n, i, gcd, lcm, x, y;
printf("请输入两个正整数 m 和 n:");
scanf("%d %d", &m, &n);
if(m<n)
{x=m;y=n;} //x为求gcd时的小数,y为求lcm的大数
else
{x=n;y=m;}
while (m % x != 0 || n % x != 0) {
x--;
}
printf("最大公约数为:%d\n", x);
//最小公倍数(LCM)的解法
printf("方法一:最小公倍数为:%d\n", x = m * n / x);
while (y % m != 0 || y % n != 0) {
y++;
}
printf("方法二:最小公倍数为:%d\n", y);
// 2.输入一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数
char str[100];
int letters = 0;
int spaces = 0;
int digits = 0;
int others = 0;
int i;
printf("请输入一行字符:");
fgets(str, 100, stdin); //存储到字符数组 str 中
for (i = 0; str[i] != '\0'; i++) {
if (isalpha(str[i])) { // 使用 isalpha函数 判断字母
letters++;
} else if (isspace(str[i])) { // 使用 isspace函数 判断空格
spaces++;
} else if (isdigit(str[i])) { // 使用 isdigit函数 判断数字
digits++;
} else {
others++;
}
}
printf("英文字母个数:%d\n", letters);
printf("空格个数:%d\n", spaces);
printf("数字个数:%d\n", digits);
printf("其他字符个数:%d\n", others);
// 3.求 Sn =a+aa+aaa+…+a…a之值,其中a是一个数字,n 表示a的位数,n、a由键盘输入。例如:2+22+222+2222+22222(此时 n=5)
int n, a, pre_num = 0, num = 0;
printf("输入n和a的值(n,a):");
scanf("%d,%d", &n, &a);
for (int i = 0; i < n; i++) {
pre_num += a * pow(10, i);
num += pre_num;
}
printf("%d\n", num);
return 0;
// 4.求1!+2!+3!+4!+…+20!
int i, j;
long long factorial = 1;
long long sum = 0;
for (i = 1; i <= 20; i++) {
factorial = 1;
for (j = 1; j <= i; j++) { //求阶乘
factorial *= j;
}
sum += factorial;
}
printf("%lld\n", sum);
// (扩展)输入一个n,求n的双阶乘 ,例如输入20,求2!+4!+…18!+20!
int n;
long long factorial = 1;
long long sum = 0;
printf("输入n的值(n>2):");
scanf("%d",&n);
for (int i = n; i > 2; i -= 2) {
factorial = 1;
for (int j = 1; j <= i; j++) {
factorial *= j;
}
sum += factorial;
}
printf("%lld\n", sum);
// 5.求2/1+3/2+5/3+8/5+...前20项
double a = 2 , b = 1 , sum = 0 ,temp;
for(int i = 1;i <= 20; i++)
{
sum = a / b;
temp = b;
b = a;
a += temp;
}
printf("前20项和为:%lf",sum);
return 0;
}