编程初级训练营复盘

​这次是编程初级训练营(牛客网)的简单复盘,选了一些平时学习时没注意到的小知识点和一些比较有意思的题目。

如果有人会小乐乐和二段数的话请务必教教我!
话不多说,Let’s go!

今天题目的娇容

  • BC14 出生日期的输入输出(%d的奇妙补零)
  • BC45 最高分数(scanf,~与EOF的三角爱情)
  • BC69,70 空心正方形和空心三角形
  • BC77 有序序列插入一个数
  • BC96 有序序列判断
  • BC98 序列中删除指定数字
  • BC99,136 序列中整数去重,去重并排序
    • 整数去重
    • 整数去重并排序
  • BC116 小乐乐改数字
  • BC117 小乐乐走台阶(也就是青蛙跳台阶问题)
  • BC119 小乐乐与字符串
  • 结尾

BC14 出生日期的输入输出(%d的奇妙补零)

如果你想将月份输成高端大气自带补零的样子,该怎么办?
手动补? 0%d? 那么12呢?
还好c够体贴,它已经为你考虑好了。
你只要使用%02就行了!买不了吃亏,买不了上当。
千万不要像我这个笨比一样用上case语句。

    scanf("%4d%2d%2d",&a,&b,&c);
    printf("year=%d\nmonth=%02d\ndate=%02d",a,b,c);

BC45 最高分数(scanf,~与EOF的三角爱情)

牛客网经常出现输入几组数的情况,如果我们熟悉scanf这个函数,那么就可以癞蛤蟆找青蛙——长得丑玩的花。
上代码:

while (scanf("%d %d %d", &a, &b, &c) != EOF)

肯定会有人在说,哎呀!=EOF好长啊,有没有更嚣张的写法呢?
当然有!

while (~scanf("%d %d %d", &a, &b, &c))

看到这个小小的~没有,它其实是和!=EOF是一个意思。

那么原因呢?
我们先要从scanf的返回值说起:
scanf的返回值取决于成功赋值的项数,比如

scanf("%d %d %d", &a, &b, &c) //这里的返回值是3
scanf("%d", &a)               //这里是1

那么如果很不幸,什么都没捞到,返回值是多少呢?
是-1,也就是EOF。(EOF要引stdio头文件)
而~是按位取反。(这个可能以后会补充,有兴趣的可以查查)
而只有-1按位取反的值是0,也就是while(0),跳出循环。

但是我们实际操作的时候可能遇到问题。
编程初级训练营复盘_第1张图片
它 停 不 下 来 了 !
因 为 没 人 告 诉 它 什 么 时 候 结 束!
在win10 系统里 快捷键ctrl c可以告诉系统到了文件末尾,这样就可以结束循环了。

BC69,70 空心正方形和空心三角形

话不多说,上图。
编程初级训练营复盘_第2张图片

刚开始,我觉着把第一行和最后一行打印,最后按规律打印中间的图案。
不就是找规律吗,谁不会啊?
那可不可以把第一行和最后一行弄进循环里面呢?
显然可以。
编程初级训练营复盘_第3张图片

我们令行为i,列为j,正方形的边长为n,然后开始找规律。
在正方形里,第0行,第n-1行永远是*,
而第0列,第n-1列永远是*。
那么——
我们就把这些全部变成 * !

#include 
int main()
{
    int n = 0;
    while (scanf("%d", &n) != EOF)
    {
        for (int i=0; i<n; i++)
        {
            for (int j=0; j<n; j++)
            {
                if (i == 0 || i == n-1 || j == 0 || j == n-1)
                printf("* "); //把0行,n-1行,0列,n-1列都改成0
                else
                printf("  ");
            }
            printf("\n");
        }
    }
    return 0;
}

同理,三角形只要当j=i时放入一个*并且限制一下每一行的长度就可以了。

#include
int main()
{
    int n = 0;
    while (scanf("%d", &n) != EOF)
    {
        for (int i=0; i<n; i++)
        {
            for (int j=0; j<=i; j++)
            {
                if (i == n-1 || j == 0 || j == i)
                printf("* ");  //把最后一行,第0列和对角线变成*
                else
                printf("  ");
            }
            printf("\n");
        }
    }
    return 0;
}

BC77 有序序列插入一个数

这题比较简单就讲讲思路。
把这放在第一题主要是和其他序列题进行对比。

如果我们想要在这个序列中插入一个10.
编程初级训练营复盘_第4张图片
我们就把10后面的数字统统往后移一位,再把10填进去。(数组一定要足够大!)
编程初级训练营复盘_第5张图片

for(i=0;i<n;i++)
    {
        if(num>arr[i])
        {
           insert=i+1;    //找到插入位置
        }
    }
    for(j=n;j>=insert;j--)   //往后循环一直到insert插入的位置
    {
        arr[j+1]=arr[j];    //往后赋值,空出一个位置给n插入
    }
    arr[insert]=num;

BC96 有序序列判断

首先我们先判断什么是有序序列。

1 2 3 4 5     //是
5 3 2 1       //是
1 1 2 5 6 7   //是
1 2 3 5 4     //不是

我们会发现,在第三个序列中,混入了两个讨厌的1,在编程的时候,就得把这种特殊情况考虑进去。

那么理一下思路:
首先分为两块:正序,倒序
然后分别判断是否有序。

先看我写的第一段代码:(这段代码是有问题的!)

    for(i=0;i<a;i++)
    {
        scanf("%d",&arr[i]);
    }
    if(arr[0]<=arr[1]) //考虑两数相同的情况
    {
        for(i=0;i<a-1;i++)
            if(arr[i]>arr[i+1])//判断是否为有序序列 
            {
                printf("unsorted"); 
                goto end;
            }
     goto p;
    }
    if(arr[0]>=arr[1]) //考虑两数相同的情况
    {
        for(i=0;i<a-1;i++)
            if(arr[i]<arr[i+1]) //判断是否为有序序列 
             {
                printf("unsorted");  
                goto end;
            }
        goto p;
    }
    p:printf("sorted");
    end:return 0;

把这段代码扔到牛客网上,是可以过的,但是不代表它没有问题。
让我们输入 5
5 5 4 3 2
结果是什么? unsortd。
为什么?因为它进入了第一个if,然后直接goto end语句,丝毫没有考虑后面的倒序if。而且不到万不得已,千万不要使用goto!
倒序和正序都要考虑,如何让电脑知道已经符合了条件呢?
可以加两个变量f1,f2,初始化为1。
我们可以再理一下思路:倒序正序都要看,就是要走两个循环。
只要不是顺序,f变为0.
两个f都为0就不为顺序。
代码如下:

    for(i=0;i<a;i++)
    {
        scanf("%d",&arr[i]);
    }
    for(i=0;i<a-1;i++)
    {
        if(arr[i]>arr[i+1])
            {
                f1=0;//不是正序,f1变为0
            }
    }
     for(i=0;i<a-1;i++)
     {
            if(arr[i]<arr[i+1])
            {
                f2=0;//不是倒序,f2变为0
            }
     }
    if(f1||f2)//f1,f2有一个为1就是顺序
        printf("sorted");
    else
        printf("unsorted");
    return 0;
}

BC98 序列中删除指定数字

这一题我觉得好玩的地方在于说是删除指定数字,但是,欸,就没删。
通过不打印来造成数字被删掉的假象。
是不是有想法了?

    for(i=0;i<a;i++)
    {
        scanf("%d",&arr[i]);
    }
    scanf("%d",&b);//要删除的数字
       for(i=0;i<a;i++)
    {
        if(arr[i]!=b)
        {
            printf("%d ",arr[i]);//打印除了b以外的所有数字
        }
    }

当然把要删除的数字改成0也是可以的,但没有这个方法简便。

BC99,136 序列中整数去重,去重并排序

整数去重

第一题可以把要删除的整数改成0,打印非零的数。

    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(i=0;i<n;i++)
    {
        for(j=i+1;j<n;j++)//从i后面的一个数开始
        {
            if(a[i]==a[j])//将重复的改为0
                a[j]=0;
        }
    }
    for(i=0;i<n;i++)
    {
        if(a[i]!=0)
        {
            printf("%d ",a[i]);//打印非零的数
        }
    }

整数去重并排序

先看看题目:
第一行,输入一个整数n,表示序列有n个整数。
第二行输入n个整数(每个整数大于等于1,小于等于1000),整数之间用空格分隔。

我们可以从这个整数的范围入手。
构建一个1001大小的数组,此时数组的元素下标是[0],[1],[2]…[1000]。
如果我们把下标为这些要处理的整数的值赋值为1,

比如 5 5 2 3 1
令arr[5]=1 arr[2]=1 arr[3]=1 arr[1]=1

再按顺序打印值为1的i的值,是不是又做到了既去重又排了序呢?

    scanf("%d",&a);
    while(a--)
    {
        scanf("%d",&i);
        arr[i]=1;//令以这些整数为名字的数组下标的值为1
    }
    i=0;
    for(i=0;i<1001;i++)
    {
        if(arr[i]==1)
        {
            printf("%d ",i);//打印值为1的数组下标
        }
    }

(可能我的说法不太严谨,可以在评论区告诉我正确的说法)

BC116 小乐乐改数字

题目:

小乐乐喜欢数字,尤其喜欢0和1。他现在得到了一个数,想把每位的数变成0或1。如果某一位是奇数,就把它变成1,如果是偶数,那么就把它变成0。请你回答他最后得到的数是多少。

最初思路:将数字存到数组里面,接着转换,最后输出。
问题:前面的0怎么办?——>检测到1后输出——>如果结果是0检测不到1怎么办——>使最后一个数在循环之外。
编程初级训练营复盘_第6张图片

代码(ver1.0):

    while(a)//a是输入的数
    {
        int b=a%10;//倒着存储
        a/=10;
        if(b%2==0)
        {
            arr[c]=0;
            c++;
        }
        else
        {
            arr[c]=1;
            c++;
        }
    }
    for(i=c-1;i>0;i--)//倒着打印
    {
        if(arr[i]==1)//找到第一个1
        {
            while(i)
            {
                printf("%d",arr[i]);
                i--;
                }
        }
    }
    printf("%d",arr[0]);//打印最后一个数

显然,这个和上一题一样,过于复杂了。
下面我们来简化代码:
设置一个变量k,一开始为1,每一次循环10.
一个变量sum,每一次循环的值是n%10
k+sum。
每次循环结束n/10。编程初级训练营复盘_第7张图片
代码(ver2.0)

    scanf("%d",&n);
    for(k=1;n;k=k*10)
    {
        t=n%10;//取出最后一个数
        if(t%2==0) 
            x=0;
        else       
            x=1;
        sum=x*k+sum;
        n=n/10;
    }
    printf("%d",sum);

BC117 小乐乐走台阶(也就是青蛙跳台阶问题)

题目:
一只青蛙 小乐乐上课需要走n阶台阶,因为他腿比较长,所以每次可以选择走一阶或者走两阶,那么他一共有多少种走法?
非常经典的递归题。
我们可以先拆分:
编程初级训练营复盘_第8张图片
拆分剩下的不是2就是1
如果是2 有两种走法:1+1和2
如果是1 只有有一种走法:就是直接走一步。

就可以写一个递归函数了。

int t(int x)
{
    if (x<=2)
        return x;
    return t(x-1)+t(x-2);
}

再写个主函数:

int main()
{
    int n=0;
    scanf("%d",&n);
    int x=t(n);
    printf("%d",x);
    return 0;
}

本题解决。

BC119 小乐乐与字符串

题目:
在庆祝祖国母亲70华诞之际,老师给小乐乐出了一个问题。大家都知道China的英文缩写是CHN,那么给你一个字符串s,你需要做的是统计s中子串“CHN”的个数。
子串的定义:存在任意下标a < b < c,那么“s[a]s[b]s[c]”就构成s的一个子串。如“ABC”的子串有“A”、“B”、“C”、“AB”、“AC”、“BC”、“ABC”。
输入描述:
输入只包含大写字母的字符串s。(1 ≤ length ≤ 8000)
输出描述:
输出一个整数,为字符串s中字串“CHN”的数量。
输入:
CCHNCHN
输出:
7

这一题主要是题干有点难懂,需要多读几遍。
我们依旧可以画图解决:
编程初级训练营复盘_第9张图片
这 7 种 是 这 样 算 的!
反正一开始我没想到。
这个图可以更直观一点。
编程初级训练营复盘_第10张图片
我们先设置c,ch,chn三个变量,初始化为0。
遇到c的时候,c++,遇到h的时候ch的值就是ch+c,表明有这么多个ch,遇到n的时候chn的值就是chn+ch。
编程初级训练营复盘_第11张图片
最后上代码:

    while(arr[i])
    {
        if(arr[i]=='C')
            c++;
        else if(arr[i]=='H')
            ch+=c;
        else if(arr[i]=='N')
            chn+=ch;
        i++;
    }
    printf("%lld\n",chn);

结尾

到这里复盘就结束了,如果还有什么问题(二段数除外,毕竟我菜)可以评论区提问,我会尽量解答或补充!
爱你们。

你可能感兴趣的:(每天刷题,快乐到家。)