C语言复习笔记: PTA题集整理

C语言复习笔记: PTA题集整理


文章目录

  • C语言复习笔记: PTA题集整理
    • @[toc]
    • C语言取模运算及辗转相除法
        • 易错内容:
        • 将/运算符当作%使用
      • 解答代码:
        • 算法实现1:
        • 算法实现2
    • 求出大于m的最小素数:PTA题集
      • 输入格式:
      • 输出格式:
      • 输入样例:
      • 输出样例:
      • 代码解答:
        • 课堂代码:存在问题 14 输出15
        • 改进后的代码:
        • 相似内容:遍历元素 并 输出或者返回数值 找素数
    • 7-3 求幂级数展开的部分和 (20分)
      • 输入格式:
      • 输出格式:
      • 输入样例:
      • 输出样例:
      • 需要注意的地方:
      • 代码内容
        • 解答代码1:
        • 修改后的代码:
    • 最佳情侣身高问题中出现的问题
      • 之前出现的问题 :
        • 由于scanf内出现了\n 导致输入出错
        • %c 前面要加上空格过滤其他字符
    • **7-2** **判断素数** **(10****分****)
        • 素数算法1:
        • 素数算法2:
        • 解决代码1:
        • 解决代码2:
    • 7-3 找出最小值 (选择排序的前身)
      • 输入格式:
      • 输出格式:
      • 输入样例:
      • 输出样例:
      • 思路分析:
          • 先输入一个整数n,然后输入n个数,先定义一个数值min用来存放当前最小元素,如果输入的数据中存在比他更小的就交换数值
      • 代码:
      • 拓展延伸:选择排序的原理及其代码实现
        • 思路:
          • 假设有六个元素需要排序, 先确定第一个元素最小,然后从第二个元素开始遍历剩余的数组元素如果有比第一个元素小的就记录元素的下标,直到找出剩余数列中的最小元素下标,然后再与第一个元素比较如果 后面元素小就和位于首位的元素互换位置
          • 为什么还要比较是否小于呢? 能否用flag标志变量来改进选择排序呢?
          • 选择排序的递归排序如何实现呢?
    • 7-1 二分查找法
      • 输入格式:
      • 输出格式:
      • 输入样例:
      • 输出样例:
      • 输入样例:
      • 输出样例:
    • 6-2 使用函数求特殊a串数列和 (20分)
      • 一 、分析:
        • 思路:
          • 核心思想 关于temp=temp*10+a 的整体性问题 对既有的数值移位再将个位数字补充完整
          • 如何实现累加不同的数字呢:——>利用函数或者改变后的累加器
          • 这个a的值也可以是整数取余之后的余数 例如 下一题中的 整数逆序部分
          • b=a*10+a a=b;的分别 : 每次累加的都是11a即 a=11a; 每次对它进行11倍数的增长
          • 关于何时使用while和for
      • 二、注意事项:
    • 7.2本题要求实现一个求整数的逆序数的简单函数。
        • 函数接口定义:
        • 裁判测试程序样例:
        • 输入样例:
        • 输出样例:
      • 一、分析
        • 开始的思路:
          • 先输入一个n然后利用一个中间变量 rem 来计算最后求得的余数 如果输入的数不为零,就对这个数进行取余,所求得余数累加起来然后再将输入的n 除以10 取余 每执行一次循环循环就对对于余数乘以10 ,最后输出sum即为逆序数
          • 需要注意的地方:若为负数 因为C语言取模标准 不会影响最结果,所以不分开讨论
      • 二、需要改进地方
      • 三、解题代码
        • 错误代码示范:
          • 只是利用了累加的思想 每次对所有余数进行求和 但是对需要*10的位置没弄明白 所以才回到你最后没能把刚开始哪一项给分离出来
        • 正确代码:
    • 6-3 使用函数输出指定范围内的完数 (20分)
        • 函数接口定义:
      • 一、分析
        • 思路:
    • 7-2 乘法口诀表
        • 输入格式
        • 输出格式
        • 样例输入
        • 样例输出
        • 解决代码:
          • 基于递归设计的解决方案
          • 先解决最里面的乘法表内容,然后紧接着执行最后一个调用函数剩余的内容
          • 核心思想是:
          • 从1到n实现累加 用来替代了开始一个for循环的内容
          • 注意设置递归边界——>即 刚开始程序最先开始执行的部分 n==1
    • 关于整型数据强制类型转换的问题
      • 代码片段
    • 7-2 猜数字 (20分)
        • 输入格式:
        • 输出格式:
      • 一、知识点:
      • 二、注意事项:
      • 三、代码片段:
    • 7-1 大小写字母转换 (15分)
        • 输入格式:
        • 输出格式:
      • 二、注意事项:
          • 什么时候使用continue 循环判断
      • 三、代码:

C语言取模运算及辗转相除法

易错内容:

  • 将/运算符当作%使用

解答代码:

算法实现1:

#include
int Gcd(int m,int n);
int main()
{
    int m,n;
    printf("请输入两个整数:\n");
    scanf("%d%d",&m,&n);
    printf("这两个数字的最大公因数是 :%d\n",Gcd(m,n));
    return 0;

    /* 
    不判断m n 大小也可行
    例如: 66 120 
    c=a%b  直接取a与b运算的余数,与a/b人的习惯不同
    那么余数r=a-a*b    最后得出r为66 此时n为120,转转相处处理后变成120%66

    关于两个正数无论大小 商为0或者1时,最后都为x
    关于正负数取模,商为0或者1时 
    如果x的绝对值大于y的绝对值   结果为x+y   否则结果为 x  -5%10=-5
    负负数取模,商为0或者1时,
                        |x|>|y| 为x-y
                        |x|<|y| 为x

    */


}
int Gcd(int m,int n)
{
    int r;
    r=m%n;
    while(r)
    {
        m=n;
        n=r;
        r=m%n;
    }
    return n;
}

算法实现2

int Gcd(int m, int n) 
{ 
// 思路:利用辗转相除法求出最大公因数,再用分子分母分别除以最大公因数
    int r;
    while(1) 
    {
        r = m % n;
        if(r == 0)//不加括号的话就只能作用于下面一句
            break;
        m = n;
        n = r;
    }
    return n;
}

求出大于m的最小素数:PTA题集

7-2 大于m的最小素数 (10分)

编程求出大于m的最小素数。

输入格式:

直接输入一个正整数

输出格式:

直接输出结果,没有任何附加格式控制。

输入样例:

12

输出样例:

13

思路1:从m+1号元素开始不断加1如果这个数能够被从2到i-1整除就继续下一次循环

代码解答:

课堂代码:存在问题 14 输出15

#include 
int main()
{
    int m,n,i,Prime;
    scanf("%d",&m);
    n=m+1;
    do
    {
        Prime=1;
        for(i=2;i<=n-1;i++)
            {
                if(n%2==0)
                        {
                            Prime=0;
                            break;
                        }
            }
            if(Prime==0)
               { n++;}

    }
    while(Prime==0);
    printf("%d\n",n);

}

改进后的代码:

#include
int Primepp(int m);
int main()
{
    int m;
    printf("请输入一个整数 :\n");
    scanf("%d",&m);
    printf("则比该数字大的最小素数为 :%d\n",Primepp(m));
    return 0;
}
int Primepp( int m)
{
    int i,j;
    //如果不是素数就为0
    for(i=m+1;;i++)
    {
        for(j=2;j<i;j++)//注意此处不是m+1;因为i的数值时会变的
        {
            if(i%j==0)
                break;
        }
//如果这个数是一个素数那么他就这里只能被他自己整除,所以这里退出循环的时候应该就是它本身,否则就继续累加
        if(j==i)
        return i;
    }
}

相似内容:遍历元素 并 输出或者返回数值 找素数

#include
int main()
{
    int n,i,j;
    scanf("%d",&n);
    for(i=2;i<=n;i++)
    {
        for(j=2;j<i;j++)
        {
            if(i%j==0) break;
        }
        if(j==i)//如果前n-1个都没发现因数就说明他是素数
            printf("%6d",i);
    }
    return 0;
}

//使用flag变量  先假设他是素数然后如果他还有其他因数flag就变为0 不输出
#include
int main()
{
    int n,i,j,flag;
    scanf("%d",&n);
    for(i=2;i<=n;i++)
    {
        flag=1;//每次循环之前都要对flag变量做初始化
        for(j=2;j<i;j++)
        {
            if(i%j==0)
            {
                flag=0;
                break;
            }
        }
        if(flag==1)printf("%6d",i);
    }
    return 0;
}

7-3 求幂级数展开的部分和 (20分)

已知函数e**x可以展开为幂级数1+x+x2/2!+x3/3!+⋯+x**k/k!+⋯。现给定一个实数x,要求利用此幂级数部分和求e**x的近似值,求和一直继续到最后一项的绝对值小于0.00001。

输入格式:

输入在一行中给出一个实数x∈[0,5]。

输出格式:

在一行中输出满足条件的幂级数部分和,保留小数点后四位。

输入样例:

1.2

输出样例:

3.3201
  • 需要注意的地方:

    • double型数据的输入与输出 %lf %f
    • 阶乘函数的返回值定义成double类型是8个字节的 int默认4 个字节
    • long long 类型的不能使用会出错误
    • 这里用迭代的方式也能解决,代码也更简洁,思想都差不多,这里就不展开了

代码内容

解答代码1:

#include
#include
double Product(int n);
int main()
{
    int n=1;
    double x,temp=1.0,sum=1.0;
    scanf("%lf",&x);
    while(temp>=0.00001)
    {
       temp=pow(x,n)/Product(n);//temp的更新必须写在循环里面才能不断的对数值进行更新 
       sum=sum+temp;
       n++;
   }
   printf("%.4f\n",sum);
   return 0;
}
double Product(int n)
{
    if(n==1)
        return 1;
    else
        return Product(n-1)*n;
}

修改后的代码:

最佳情侣身高问题中出现的问题

  • 之前出现的问题 :

    • 由于scanf内出现了\n 导致输入出错

    • %c 前面要加上空格过滤其他字符

#include 
int main()
{
    int N,i;
    float h;
    char a;
    scanf("%d",&N);//scanf后面不要加\n 否则要多敲一次回车
    for(i=1;i<=N;i++)//漏了=
    {
        scanf(" %c %f",&a,&h);
        if(a=='M')
            printf("%.2f\n",h/1.09);
        if(a=='F')
            printf("%.2f\n",h*1.09);
    }
    return 0;
}

7-2 判断素数 **(10)

素数算法1:

int prime( int p )
//判断一个数是不是素数,最简便的方法都是排除法,而在排除法中,有最直观的  从2到p-1的 遍历算法;
//也有优化之后的改进算法:
//因为假如p是合数,必然存在非1的两个约数n1和n2,其中n1<=sqrt(p),n2>=sqrt(p)。由此我们可以改进上述方法优化循环次数;
{
    int i;
    if(p<3)
        return p>1;//如果p为素数则输出1,合数则输出0;
    for(i=2;i*i<=p;i++)//乘方处理不必调用sqrt();
    //此处在p=3时,其实也可以进入判断,主要是为了防止输入值为小于等于2的数;
    //即if(p<=3)也嵙;
    {
        if(p%i==0)
            return 0;//只要有一个因子就直接返回0;
    }
return 1;//若从2---》 sqrt(p),没有一个因子,把么这个数一定为素数;
}

素数算法2:

int prime(int p )
// 关于验证素数的第三种算法:质数还有一个特点,就是它总是等于 6x-1 或者 6x+1,其中 x 是大于等于1的自然数;
//
// 下面解释原理:
// 6x+2能被2整除,6x+3__3  6x+4__2  6x___6 ,
// 所以质数一定在6x-1 , 6x+1 两类数值中,将循环步长设置为6;
// 由于这个数值p是由人为输入的并且p在3<=p<=6范围内6x-1 ,6x+1 都为质数 所以能保证(x>=1),
// 即 6x+5 等同于 6x-1;
// 就只有 6x+1 和 6x+5 (即等同于6x-1) 可能是质数了。所以循环的步长可以设为 6,然后每次只判断 6 两侧的数即可;
// 算法实现:
{
    if(p<=3)
        return p>1;
    // 不在6的倍数两侧的一定不是素数;
    if(p % 6 != 1 && p % 6 != 5)
        return 0;
    for (int i = 5; i*i<= p; i += 6)//借用算法2的结论i>>>sqrt(p)
    {
        if (p % i == 0 || p % (i + 2) == 0)
            return 0;
    }
    return 1;
}

解决代码1:

#include
int main()
{
    int i,j,n,N;
    scanf("%d",&N);
    for(i=0;i<N;i++)//不用数组也可以实现输入
    {
        scanf("%d",&n);
        for(j=2;j*j<=n;j++)//此处判断是否需要化为整数呢 Bug点
        {
            if(i%j==0)//i与j的位置为什么此处不可以交换呢  多了一吋循环条件
                break;
        }
        if(j==i)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

解决代码2:

利用标志变量flag

#include 
#include 
int main()
{
    int N, x, i, flag;
    scanf("%d", &N);
    while(N--)
    {
        scanf("%d", &x);
        flag = 1;
        for(i = 2; i <= sqrt(x); i++)
        {
            if(x % i == 0)
            {
                flag = 0;
                break;
            }
        }
        if(x == 1 || flag == 0)
            printf("No\n");
        else
            printf("Yes\n");
    }
    return 0;
}

7-3 找出最小值 (选择排序的前身)

本题要求编写程序,找出给定一系列整数中的最小值。

输入格式:

输入在一行中首先给出一个正整数n,之后是n个整数,其间以空格分隔。

输出格式:

在一行中按照“min = 最小值”的格式输出n个整数中的最小值。

输入样例:

4 -2 -123 100 0

输出样例:

min = -123

思路分析:

  • 先输入一个整数n,然后输入n个数,先定义一个数值min用来存放当前最小元素,如果输入的数据中存在比他更小的就交换数值

代码:

#include 

int main()
{
    int n, i, k, min;
    scanf("%d", &n);
    for(i = 0; i < n; i++){
        scanf("%d", &k);
        if( k < min )    min = k;
    }
    printf("min = %d", min);

    return 0;
}

拓展延伸:选择排序的原理及其代码实现

思路:

  • 假设有六个元素需要排序, 先确定第一个元素最小,然后从第二个元素开始遍历剩余的数组元素如果有比第一个元素小的就记录元素的下标,直到找出剩余数列中的最小元素下标,然后再与第一个元素比较如果 后面元素小就和位于首位的元素互换位置
  • 为什么还要比较是否小于呢? 能否用flag标志变量来改进选择排序呢?
  • 选择排序的递归排序如何实现呢?

7-1 二分查找法

用二分法在一个有序数列{1,2,3,4,5,6,7,8,9,10}中查找key值,若找到key则输出其在数组中对应的下标,否则输出not found。

输入格式:

直接输入一个要查找的正整数key。没有其它任何附加字符。

输出格式:

找到则在一行中按照“weizhi:下标”的格式输出其在数组中对应的下标,否则输出not found。

输入样例:

4

输出样例:

weizhi:3

输入样例:

15

输出样例:

not found

6-2 使用函数求特殊a串数列和 (20分)

给定两个均不超过9的正整数an,要求编写函数求a+a**a+aaa++⋯+a**aana)之和。

一 、分析:

思路:

  • 核心思想 关于temp=temp*10+a 的整体性问题 对既有的数值移位再将个位数字补充完整
    如何实现累加不同的数字呢:——>利用函数或者改变后的累加器
    这个a的值也可以是整数取余之后的余数 例如 下一题中的 整数逆序部分
  • b=a*10+a a=b;的分别 : 每次累加的都是11a即 a=11a; 每次对它进行11倍数的增长
  • 关于何时使用while和for
#include 

int fn( int a, int n );
int SumA( int a, int n );

int main()
{
    int a, n;

    scanf("%d %d", &a, &n);
    printf("fn(%d, %d) = %d\n", a, n, fn(a,n));
    printf("s = %d\n", SumA(a,n));

    return 0;
}

/* 你的代码将被嵌在这里 */
int fn(int a,int n)
{
    int temp=0;
    for(int i=1;i<=n;i++)
    {
        temp=temp*10+a;//移位再加上a
    }
    return temp;
}
int SumA(int a,int n)
{
    int sum=0;
    for(int i=1;i<=n;i++)//不能通过累加器实现
    {
       sum+=fn(a,i);
    }
    return sum;
}

二、注意事项:

7.2本题要求实现一个求整数的逆序数的简单函数。

函数接口定义:

int reverse( int number );

其中函数reverse须返回用户传入的整型number的逆序数。

裁判测试程序样例:

#include 

int reverse( int number );

int main()
{
    int n;

    scanf("%d", &n);
    printf("%d\n", reverse(n));

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

-12340

输出样例:

-4321

一、分析

开始的思路:

  • 先输入一个n然后利用一个中间变量 rem 来计算最后求得的余数 如果输入的数不为零,就对这个数进行取余,所求得余数累加起来然后再将输入的n 除以10 取余 每执行一次循环循环就对对于余数乘以10 ,最后输出sum即为逆序数
  • 需要注意的地方:若为负数 因为C语言取模标准 不会影响最结果,所以不分开讨论

二、需要改进地方

三、解题代码

错误代码示范:

  • 只是利用了累加的思想 每次对所有余数进行求和 但是对需要*10的位置没弄明白 所以才回到你最后没能把刚开始哪一项给分离出来
    int n,rem,sum=0;
    scanf("%d",&n);
    rem=n;
    while(rem)
    {
        sum=rem*10+rem%10;
        rem=n/10;
    }

正确代码:

int reverse(int number)
{
    int temp=0;
    while(number)//无论正负都进入循环,不必再进行分类
    {
        temp=temp*10+number%10;//递推法求逆序数
        number=number/10;
    }
    return temp;
}

6-3 使用函数输出指定范围内的完数 (20分)

本题要求实现一个计算整数因子和的简单函数,并利用其实现另一个函数,输出两正整数mn(0<mn≤10000)之间的所有完数。所谓完数就是该数恰好等于除自身外的因子之和。例如:6=1+2+3,其中1、2、3为6的因子。

函数接口定义:

int factorsum( int number );
void PrintPN( int m, int n );

其中函数factorsum须返回int number的因子和;函数PrintPN要逐行输出给定范围[m, n]内每个完数的因子累加形式的分解式,每个完数占一行,格式为“完数 = 因子1 + 因子2 + … + 因子k”,其中完数和因子均按递增顺序给出。如果给定区间内没有完数,则输出一行“No perfect number”。

一、分析

思路:

7-2 乘法口诀表

请编写程序,输出 n×n 的乘法口诀表。

输入格式

n

输出格式

n×n 的乘法口诀表。

样例输入

5

样例输出

1x1= 1
1x2= 2 2x2= 4
1x3= 3 2x3= 6 3x3= 9
1x4= 4 2x4= 8 3x4=12 4x4=16
1x5= 5 2x5=10 3x5=15 4x5=20 5x5=25

注:乘号为小写字母 x;乘积域宽 2 格(右对齐);两列之间空 1 格;行末没有空格。

解决代码:

  • 基于递归设计的解决方案
  • 先解决最里面的乘法表内容,然后紧接着执行最后一个调用函数剩余的内容
  • 核心思想是:
    • 从1到n实现累加 用来替代了开始一个for循环的内容
    • 注意设置递归边界——>即 刚开始程序最先开始执行的部分 n==1
    • 递归之后里面就是单纯的内层循环的内容     (i 从1开始了)*错误

    • 用递归来解决 重复发生的事情 比如外层的循环次数

    #include
    #include
    void PrintMultiplcationTable(int n)
    {
        if(n==1)
        {
            printf("1x1= 1");
        }
        else
        {
            PrintMultiplcationTable(n-1);
            printf("\n");
            for(int i=1;i<=n;++i)
            {
                printf("%dx%d=%2d",i,n,i*n);
                if(i<n) printf(" ");
            }
        }
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        PrintMultiplcationTable(n);
        return 0;
    }
    
    

关于整型数据强制类型转换的问题

代码片段

#include
int main()
{
    int a[10],min=0;
    int sum=0;
    for(int i=0;i<10;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=0;i<10;i++)
    {
        if(a[min]>a[i])
            min=i;
        sum+=a[i];
    }
    printf("最小值为: %d\n平均值为:%f\n",a[min],sum/10.0);
    //这里难道又新开辟了一片专门的存储空间吗?
    //sum为int类型   sum/10.0就变成了double类型 当然输出的时候就必须用%f了
    //float与double类型都是用%f来输出  而scanf在float上面是%f在double上面是%lf
    //scanf函数的使用一定不要加上那个\n;
    //   强制类型转换的方式为 (double)sum 或者 sum*1.0乘上一个小数之后就会自动转化为浮点数输出
    //   如果这里的sum用的是double类型那么 就算输出时不加上sum*1.0  double sum=0.0  等操作她也会输出一个浮点数
    return 0;
}

7-2 猜数字 (20分)

一群人坐在一起,每人猜一个 100 以内的数,谁的数字最接近大家平均数的一半就赢。本题就要求你找出其中的赢家。

输入格式:

输入在第一行给出一个正整数N(≤104)。随后 N 行,每行给出一个玩家的名字(由不超过8个英文字母组成的字符串)和其猜的正整数(≤ 100)。

输出格式:

在一行中顺序输出:大家平均数的一半(只输出整数部分)、赢家的名字,其间以空格分隔。题目保证赢家是唯一的。

一、知识点:

**1. 关于其struct声明的位置,也就是这段代码要放到哪里。**同样这也是具有作用域的。

这种声明如果放在任何函数的外面,那么则可选标记可以在本文件中,该声明的后面的所有函数都可以使用。

二、注意事项:

三、代码片段:

#include
#include
#define N 10000
struct guess
{
    char name[9];
    //忘记字符数组的最后一位\0占有一个位置 读题造成的失误
    int num;
}s[N],*p=s;
//定义指针变量p指向结构体数组首元素  以基类型为单位进行移动 
int main()
{
    int sum=0,avr,n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%s %d",(p+i)->name,&(p+i)->num);
        //p+i输出是可以输出但是类型不匹配
        // p+i 为当前元素的首地址 恰好也是字符数组的首地址才恰好能写入
        //(p+i)->name
        //&(p+i)->num)优先级关系
        sum+=(p+i)->num;
    }
    avr=(sum/n)/2;
    int min=0,j=1;
    for(;j<n;j++)
    {
        if(abs((p+min)->num-avr)>abs((p+j)->num-avr))
            min=j;
    }
    printf("%d %s\n",avr,(p+min)->name);
    return 0;


}

7-1 大小写字母转换 (15分)

输入一行字符,以回车符 ‘\n’ 结束,将其中的大写字母转换为相应的小写字母后输出,小写字母转换为相应的大写字母后输出,其他字符按原样输出。

输入格式:

输入一行字符,以回车符 ‘\n’ 结束。

输出格式:

将输入字符串中的大写字母转换为相应的小写字母后输出,小写字母转换为相应的大写字母后输出,其他字符按原样输出。

二、注意事项:

  • 什么时候使用continue 循环判断

三、代码:

#include
#define N 20
int main()
{
    char a[N];
    gets(a);
    for(int i=0;a[i]!='\0';i++)
    {
        if(a[i]>='A'&&a[i]<='Z')
            a[i]+=32;
        else if(a[i]>='a'&&a[i]<='z')
            a[i]-=32;
    }
    puts(a);
    return 0;
}

你可能感兴趣的:(考试复习)