pta刷题总结——编程题篇(c程序设计书)

1 . 闰年

输出21世纪中截止某个年份以来的所有闰年年份。注意:闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。

  • 注意一点:2000年属于20世纪最后一年,所以21世纪应该是从2001年到2100年(包含)

2 . 找出最小值

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

  • 因为给出n个数,直到是n个,所以可以循环输入并比较
  • 找出最小,只需要定义一个存最小就好了,每输入一个就与它比较,若小于最小就存入
  • 特别注意,定义时一定是将第一个存入的存为最小值的初始值,切忌随便设一个数。
#include<stdio.h>
int main(void){
    int n,i,min,m;
    scanf("%d",&n);
    scanf("%d",&m);
    min=m;
    for(i=1;i<n;i++){
        scanf("%d",&m);
        min=m>min?min:m;
        
    }
    printf("min = %d",min);
    return 0;
}

3 . 最大公约数和最小公倍数

m和n

  • 明确m*n=他们最大公约数和最小公倍数相乘
  • 最大公约数可以通过辗转相除法计算出来
  • 先求出最大公约数再通过公式求出最小公倍数
/*首先明确求解方法,用辗转相除法先求出最大公约数,然后用最大公约数*最小公倍数=m*n求出最小公倍数*/
#include<stdio.h>
int main(void){
    int m,i,n;
    scanf("%d%d",&m,&n);
    i=m*n;//用来最后求最小公倍数的
    int r;
    while(r=m%n){
        m=n;
        n=r;
    }
    printf("%d %d",n,i/n);
    return 0;
}

4 . 打印菱形图案

本题要求编写程序,打印一个高度为n的、由“*”组成的正菱形图案

输出样例:

      * 
    * * * 
  * * * * * 
* * * * * * * 
  * * * * * 
    * * * 
      * 
  • 此题关键:对称!!!
  • 怎么个对称,关于中间那一行对称 
j<=2*fabs(m-i)
  • 关键理解:m是中间那一行的行数,i是遍历每一行时对应的行数,m-i取绝对值就是距离m的距离!!!对称时距离相同哇。
#include<stdio.h>
#include<math.h>
int main(void){
    int n,j,i;
    scanf("%d",&n);
    int m;
    m=(n+1)/2;//存放中间的行数
    for(i=1;i<=n;i++){//遍历每一行进行打印
        for(j=1;j<=2*fabs(m-i);j++){
            printf(" ");//打印空格,距离每加一打印两个空格
        }
        for(j=1;j<=n-2*fabs((m-i));j++){
            printf("* ");//打印* 
        }
        printf("\n");
    }
    return 0;
}

5 .  猴子吃桃问题

一只猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个;第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第N天早上想再吃时,见只剩下一个桃子了。问:第一天共摘了多少个桃子?

输入3,输出10

  • 到第n天早上想吃,也就是说第n天没吃,所以一共是吃了n-1天
  • 特别注意数学公式x与y的转换,很容易出错
#include<stdio.h>
int main(void){
    int n;
    int sum=0,i;
    int y=1;
    scanf("%d",&n);
    for(i=1;i<=n-1;i++){
        sum=(y+1)*2;
        y=sum;
    }
    printf("%d",sum);
}

6 . 兔子繁衍问题

一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到第3个月后每个月又生一对兔子。假如兔子都不死,请问第1个月出生的一对兔子,至少需要繁衍到第几个月时兔子总数才可以达到N对?

输入格式:

输入在一行中给出一个不超过10000的正整数N。

输出格式:

在一行中输出兔子总数达到N最少需要的月数。

输入样例:

30

输出样例:

9
/*首先明确思路:兔子繁衍问题就是那个1,1斐波那契数列,所以求第几个月能到n就是该数列前多少项大于。*/

#include<stdio.h>
int main(void){
    int n;
    scanf("%d",&n);
    int month=3;
    int x1,x2,x;
    x1=x2=1;
    int sum=2;
    x=x1+x2;
    if(n==1)printf("1");
    else if(n==2)printf("3");
    else {while(x<n){
        x1=x2;
        x2=x;
        x=x1+x2;
        month++;
    }
         printf("%d",month);}
    return 0;
}

也可以用数组,暂时没写出测试点完全通过的代码

7 .  单词首字母大写

本题目要求编写程序,输入一行字符,将每个单词的首字母改为大写后输出。所谓“单词”是指连续不含空格的字符串,各单词之间用空格分隔,空格数可以是多个。

  • 这个和书上的统计单词个数很类似
  • 两点:首先,在新单词前面要经历过空格,且现在的不是空格
  • 实现第一点就是用if,如果为空格时就改变标志的值,在else if加一个条件就是标志值改变,执行了else if就表示现在的不是空格,那么标志的值改回来,这样同一个单词的字母才不会循环执行
  • 与书上多了一点限制,因为很有可能输入时该单词首字母就是大写,所以加上判断,当首字母是小写时进行转换。
//思路:如书上输入空格数单词个数一样,将它看作一个整体,判断是一个新单词时就将其输入的字符改写为大写。
#include<stdio.h>
int main(void){
    char ch;
    int flag=1;
    while((ch=getchar())!='\n'){
        if(ch==' '){
            flag=1;
        }
        else if(flag){
            if(ch>=97&&ch<=122)ch=ch-'a'+'A';
            flag=0;
        }
        putchar(ch);
    }
    return 0;
}

8 . 恺撒密码加密

输入一个偏移量,若该数>0往右平移,若该数<0往左平移

  • 特殊的是<0时往左平移,这个时候要分情况讨论,因为它可能过边界,所以就需要单独讨论
	while(a[i]!='\0'){
		if(offest<0){
			if(a[i]+offest<65||a[i]+offest<97&&a[i]>'a'){
				a[i]=a[i]+max+offest;
			}
			else a[i]=a[i]+offest;
		}
		i++;
	}

特别注意这个代码 

a[i]+offest<97&&a[i]>'a'
  • 一定不能忘记&&的内容,若是忘记,那么当a[i]是大写时68-1=67,也是小于97的,就会造成错误处理!!!!

如上图,大写S不应该进入if中的,因为少了&&所以当为大写的时候总是满足判断小写的条件,导致S进入加了26再往左移。

  • 下面是一个简单向又移动的代码,值得一提的是它在最后到边界时的处理,事实上在之前的循环右移中就可以用这种思路,加个外循环循环平移m次就好 
#include<stdio.h>
int main(void){
    char a[81];
    gets(a);
    int i=0;
    while(a[i]!='\0'){
        if(a[i]>=65&&a[i]<=90||a[i]>=97&&a[i]<=122){
            if(a[i]>=65&&a[i]<=90){
                a[i]=a[i]-'A'+'a';
                if(a[i]=='z')a[i]='a';
                else a[i]+=1;
            }//大写字母变成小写字母;
            else {
                a[i]=a[i]-'a'+'A';
                if(a[i]=='Z')a[i]='A';
                else a[i]+=1;
            }//因为前面已经做出判断,所以a【i】不是大写字母就只能是小写字母了

        }
        i++;
    }
        puts(a);
        return 0;
}

9 .  求最大值及其下标

  • 得到了下标还怕不知道对应的最大值吗,怎么可能!!!
  • 用条件缩写形式别怕,反正?前是条件,条件当然可以是表达式
int main(void) {
    int n;
    scanf("%d", &n);
    int array[10];
    for (int i = 0; i < n; i++) {
        scanf("%d", &array[i]);
    }
    // 假设数组中的第一个元素最大,后续比较过程中进行更新
    int maxValIndex = 0;
    for (int i = 1; i < n; i++) {
        maxValIndex = array[i] > array[maxValIndex] ? i : maxValIndex;
    }
    printf("%d %d", array[maxValIndex], maxValIndex);
    return 0;
}

10 .  将数组中的数逆序存放

本题要求编写程序,将给定的n个整数存入数组中,将数组中的这n个数逆序存放,再按顺序输出数组中的元素。

输入样例:

4
10 8 1 2

输出样例:

2 1 8 10
  • 一定要关注它的输入形式,一个数字一个空格,先输入一个字然后通过判断输入字符是否是空格当作输入结束标志,当到最后一个输入的是换行而不是空格。
#include<stdio.h>
int main(void){
    int n;
    int a[100];
    int i=1,j;
    scanf("%d",&n);
    scanf("%d",&a[0]);
    while(getchar()==' '){
        scanf("%d",&a[i]);
        i++;
    }
    for(j=i-1;j>0;j--)
        printf("%d ",a[j]);
    //注意是从最大开始的,所以应该j>=0!
    printf("%d",a[j]);
    return 0;
}
  • 注意输出最后一个不带空格,所以在输出最后一个的时候要单独处理,也就是单独输出,不加空格。 

11 .  找出不是两个数组共有的元素

  • 可能两个数组中所有的数都不是共有元素,所以在定义存放不是共有元素的数组时,它的大小应该大于两个数组大小之和以防止数组溢出
  • 必须两个数组全都遍历,每个数组都要遍历看是否有不是共有元素的存入数组c中
  • 在输出不是共有元素的数组c时一定要进行判断,看前面是否输出过相同的数,没有输出过才将它输出,毕竟很可能b数组没有的,a数组有两个,都存入数组c了
#include<stdio.h>
int main(void){
    int n1,n2;
    int flag;
    int i,j;
    int c[40];
    int a[20],b[20];
    scanf("%d",&n1);
    for(i=0;i<n1;i++){
        scanf("%d",&a[i]);
    }
    int n=0;
    scanf("%d",&n2);
    for(i=0;i<n2;i++)scanf("%d",&b[i]);
    for(i=0;i<n1;i++){//遍历数组a,找b中没有的
        flag=1;
        for(j=0;j<n2;j++){
            if(a[i]==b[j]){
                flag=0;break;
            }
        }
        if(flag)c[n++]=a[i];
    }
    for(i=0;i<n2;i++){
        flag=1;
        for(j=0;j<n1;j++){
            if(b[i]==a[j]){
                flag=0;break;
            }
        }
        if(flag)c[n++]=b[i];
    }
    printf("%d",c[0]);
    for(i=1;i<n;i++){//遍历c数组每一个数
        flag=1;
        for(j=0;j<i;j++){
            if(c[i]==c[j]){//判断前面是否有输出过,避免重复输出哦
                flag=0;break;
            }
        }
        if(flag){
            printf(" %d",c[i]);
        }
    }
    return 0;
}

12 .  矩阵运算

给定一个n×n的方阵,本题要求计算该矩阵除副对角线、最后一列和最后一行以外的所有元素之和。副对角线为从矩阵的右上角至左下角的连线。

  •  找出特点,既然是计算除了它们以外的和,那么就在遍历的时候做出判断就行了
#include<stdio.h>
int main(void){
    //副对角线的特点:行列标相加i+j=n-1;所以只需设置一个变量,另一个用减法表示即可
    int i;
    int n;
    int j;
    int a[20][20];
    int sum=0;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        for(j=0;j<n;j++)scanf("%d",&a[i][j]);
    }
    //上一次写这个题目的思路是全部相加再减去题目中的除了;
    //现在转念一想,可以在遍历时判断是否不属于题目中的不要加的部分,只有不属于时才将其加进去。
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            //不是最后一行即i!=n-1;不是最后一行即j!=n-1;不是副对角线就是i!=n-1-j;
            if(j!=n-1-i&&i!=n-1&&j!=n-1)sum+=a[i][j];
        }
    }
    printf("%d",sum);
    return 0;
}

13 . 方阵循环右移

本题要求编写程序,将给定n×n方阵中的每个元素循环向右移m个位置,即将第0、1、⋯、n−1列变换为第n−m、n−m+1、⋯、n−1、0、1、⋯、n−m−1列。

输入格式:

输入第一行给出两个正整数m和n(1≤n≤6)。接下来一共n行,每行n个整数,表示一个n阶的方阵。

输出格式:

按照输入格式输出移动后的方阵:即输出n行,每行n个整数,每个整数后输出一个空格。

输入样例:

2 3
1 2 3
4 5 6
7 8 9

输出样例:

2 3 1 
5 6 4 
8 9 7 
  • 这里特别注意就是在循环右移时的覆盖问题
  • 因为怕覆盖,所以先将最后一个数用一个临时变量存放,这样就不用怕覆盖,然后因为空出的是最后一个,所以从后面开始移动而不是从前面开始移动
  • 最后再将临时变量存的最后一个数赋给第一个数,以此达到了循环移动一位的作用,所以再以外循环为循环移动 m位
#include<stdio.h>
int main(void){
    int n,m,k,temp,i,j;
    int a[20][20];
    scanf("%d",&m);
    scanf("%d",&n);
    for(i=0;i<n;i++){
        for(j=0;j<n;j++)scanf("%d",&a[i][j]);
    }
    m%=n;
   
    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            temp=a[j][n-1];
            //for(k=1;k<n;k++)a[j][k]=a[j][k-1];
            //上面这个错了,它从前面开始往后赋值,往后就会覆盖,最后输出的就会没有2 5 8这一行数
            //因为我们是将最后一个赋给第一个,相当于先将最后一个位置空出来,所以先从后面往前填才不会出现覆盖的情况。
            for(k=n-1;k>0;k--)a[j][k]=a[j][k-1];
             a[j][0]=temp;
        }
       
    }
    for(i=0;i<n;i++){
        for(j=0;j<n;j++)printf("%d ",a[i][j]);
        printf("\n");
    }
    return 0;
}

14 . 计算天数

本题要求编写程序计算某年某月某日是该年中的第几天。

输入格式:

输入在一行中按照格式“yyyy/mm/dd”(即“年/月/日”)给出日期。注意:闰年的判别条件是该年年份能被4整除但不能被100整除、或者能被400整除。闰年的2月有29天。

输出格式:

在一行输出日期是该年中的第几天。

输入样例1:

2009/03/02

输出样例1:

61
  •  注意这里为了使月份与下标相对应,a[0]存放0来占位,后面月份和下标对应啦,只要不用0就好啦
  • 现在在的那个月直接加上该月的天数就好了,不要加一整个月的
#include<stdio.h>
int main(void){
    int day,year,month,i;
    scanf("%d/%d/%d",&year,&month,&day);
    //注意:要使月份与数组对应相同,应将一维数组中的第一个设为0,占位,让后续月份对应数组下标
    int a[2][13]={{0,31,28,31,30,31,30,31,31,30,31,30,31},
    {0,31,29,31,30,31,30,31,31,30,31,30,31}};
    int leap;
    leap=year%4==0&&year%100!=0||year%400==0;
    for(i=month-1;i>0;i--){
        //day+=a[leap][month]
        //粗心:此时已经用i代替month
        day+=a[leap][i];
    }
    printf("%d",day);
    return 0;
}

 15 .  查找指定字符
 

本题要求编写程序,从给定字符串中查找某指定的字符。

输入格式:

输入的第一行是一个待查找的字符。第二行是一个以回车结束的非空字符串(不超过80个字符)。

输出格式:

如果找到,在一行内按照格式“index = 下标”输出该字符在字符串中所对应的最大下标(下标从0开始);否则输出"Not Found"。

输入样例1:

m
programming

输出样例1:

index = 7
  •  注意因为是要找到最大下标,所以第一次找到后不用打破循环,一直到所有循环完更新
  • printf也可以用条件语句输出呢
  • 巧妙的一点,给index初始化一个原来没有的值,在条件判断中看该值是否改变就可以知道有没有查到一样的了
#include <stdio.h>
int main () {
    int i = 0,index = -1;
    char c, str[81];
    scanf("%c\n", &c);
    gets(str);
    // scanf("%[^\n]", str);  // 用%s输入字符串,遇到空格会停止,要把空格包括在内可以用"%[^\n]",会读到'\n'为止 
    while (str[i] != '\0') {
        if (str[i] == c) index = i;
        i++;
    }
    printf(index==-1?"Not Found":"index = %d",index);
    return 0;
}

16 . 字符串逆序

  • 通过指针一头一尾互换位置来达到目的
  • 头加尾减,注意尾要减1哦,因为首地址偏移n个元素那么多了一个首地址也就是字符串结束符
void reverse(char* left, char* right)
{
	while (left<right)
	{
		char tmp = 0;
		tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}
int main()
{
	char arr[100] = { 0 };
	gets(arr);//获取字符串
	//将字符串倒置
	int len = strlen(arr);//计算字符串长度,以求最后一位的地址
	reverse(arr, arr+len-1);//进行倒置
    printf("%s\n",arr);
    return 0;
}

17 . 选择法排序

  • 具体见选择排序专题
  • 注意不可以用异或,万一要互换的是两个相同的数那么会将他们异或成0
#include<stdio.h>
int main(void){
    int n,i,j,max,temp;
    int a[10];
    scanf("%d",&n);
    for(i=0;i<n;i++)scanf("%d",&a[i]);
    for(i=0;i<n-1;i++){
        max=i;
        for(j=i+1;j<n;j++){
            if(a[j]>a[max])max=j;
        }//问题:第一个输入的数无论是什么都会变成0
        //a[i]^=a[max]^=a[i]^=a[max];
//不要使用异或,异或是可以交换两个值,但是仅限两个不同值,若将两个相同的值进行上述三次异或
//不仅不可以交换两个值,还会将两个值都归0.所以若要将两个值归0,可以将它与他自己或与他相同的值进行异或
        temp=a[i];
        a[i]=a[max];
        a[max]=temp;
    }
    for(i=0;i<n-1;i++)printf("%d ",a[i]); 
    printf("%d",a[n-1]);
    return 0;
}

18 . 求一批整数中出现最多的个位数字

给定一批整数,分析每个整数的每一位数字,求出现次数最多的个位数字。例如给定3个整数1234、2345、3456,其中出现最多次数的数字是3和4,均出现了3次。

输入格式:

输入在第1行中给出正整数N(≤1000),在第二行中给出N个不超过整型范围的非负整数,数字间以空格分隔。

输出格式:

在一行中按格式“M: n1 n2 ...”输出,其中M是最大次数,n1、n2、……为出现次数最多的个位数字,按从小到大的顺序排列。数字间以空格分隔,但末尾不得有多余空格。

输入样例:

3
1234 2345 3456

输出样例:

3: 3 4
  • 很巧妙的一点,数字可以和数组下标相对应,所以直接以该数字为下标加值就可以了
  • 将每个数看作一个数组元素存入
  • 特别处理,当该数是0的时候,直接将存数字的元素值加一 
  • 特别注意就是很可能是有一样的出现最大次数,所以最后遍历存出现次数的数组,若为最大次数就输出其下标也就是对应数字
/*关键:每个整数当成一个元素存入数组中,注意存入数组后,该元素也就是
一个整数,可以进行取余等操作,然后进行判断。
巧妙:新建一个数组,数组下标即表示对应数字,当符合时对应元素加一,即代表
该数字出现的次数*/
#include<stdio.h>
int main(void){
    int a[1000];
    int i;//对应下标数字中数组元素存入的就是该数字出现的次数
    int n;
    int b[10]={0};
//特别注意:当a为0时,是一个特殊的值,所以要单独拎出来讨论。
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(i=0;i<n;i++){//遍历数组
        if(a[i]==0)b[0]++;
        while(a[i]!=0){
            b[a[i]%10]++;//将数字存入
            a[i]/=10;//存入最后一个数字后,数字要更新
        }
    }
    int max=b[0];//因为只要找出最大值,不用进行排序,所以只要遍历找出就好啦
    //找出最大值,最后再循环一遍找出与最大值相等的就是对应下标
    for(i=1;i<10;i++){
        if(b[i]>max){
            max=b[i];
        }
    }
    printf("%d:",max);
    for(i=0;i<10;i++){
        if(b[i]==max)printf(" %d",i);
    }
    return 0;
}

 

  • 6
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值