用C语言解决逢7击掌问题

用C语言解决“逢7击掌”问题

原题目

  • 这是一道PTA题目,原题是这样的:

    一群人围坐成一圈玩报数的游戏。

    游戏规则是:从1开始报数,若遇到7的倍数或者个位为7的数则击掌代替,若犯错则要受罚。

    可是这些人都太聪明了,竟然没人犯错!

    请问同样聪明的你,现在当报数到 n 时,击掌共次数 c 是多少?

    输入格式:

    n

    输出格式:

    c

    输入样例:

    21

    输出样例:

    4

第一次尝试

  • 一开始,我觉得最先能想到办法是利用循环:

    当数字是7的倍数或者个位数为7,那么计数器+1

    7的倍数,C语言的表达式为:i%7 == 0

    个位数为7,C语言的表达式为:i%10 == 7

    这是最为清晰的一个思路,非常容易理解

    相应完整代码为

    #include <stdio.h>
    int main()
    {
       int n, c = 0;  //n是待输入数据,c是计数器
       scanf("%d", &n);
       for (int i = 1; i <= n; i++) {
           //如果符合条件,计数器+1
           if ( i%7 == 0 || i%10 == 7)
               c++;
       }
       printf("%d\n",c);
       return 0;
    }
    

    (语法标准采用C99)

  • 用GCC编译器运行上面的代码:

    [此处放图片]

    那么显然,我们认为在GCC上通过了


  • 提交系统后?

    [此处放图片]

    系统提示超时,说明我们得优化思路!

优化超时问题

  • 这里我们观察规律:

    每70个数里会有16个数击掌:

    1-70

    7的倍数:
    14、21、28、35、42、49、56、63、70

    个位数为7:
    17、27、37、47、57、67

    个位数为7且为7的倍数:
    7

    共16个

    71-140

    7的倍数:
    84、91、98、105、112、119、126、133、140

    个位数为7:
    87、97、107、117、127、137

    个位数为7且为7的倍数:
    77

    共16个

    ……

    所以办法是:

    1. 先计算有多少个70个为一组的组数(×16,得到前面的击掌数)
    2. 再计算剩余的不满70个数的那一组的击掌数

    修改后的代码:

    #include <stdio.h>
    int main()
    {
       int n, c = 0, cnt;
       //n是待输入数据,c是后几个数的计数器,cnt计算有多少个70个为一组的组数
       scanf("%d", &n);
       /*
       寻找规律:每70个数会有16个数击掌,只要判断剩下的
       */
       cnt = n / 70;  //计算有多少个70个为一组的组数
       n %= 70;       //将n变为最后剩余不满70个数的一组
       for (int i = 1; i <= n; i++) {
           //如果符合条件,后几个数的计数器+1
           if ( i%7 == 0 || i%10 == 7)
               c++;
       }
       c = c + cnt * 16;  //计算总共的击掌数
       printf("%d\n",c);
       return 0;
    }
    

    (语法标准采用C99)


  • 提交系统后

    [此处引用图片]

    终于不超时了!

算法优化

  • 实际上,本题不使用循环也能完成:

    我们只需观察最后一个数n本身,利用算出1~n中7的倍数,个位数为7的数,最后计数相加

    请看代码:

    #include <stdio.h>
    int main()
    {
       int n; //待输入数据
       int c = 0; //计数器
       scanf("%d",&n);
       
       c += n / 7;              //是7的倍数
       c += (n - 7) / 10 + 1;   //个位数为7
       c -= (n - 7) / 70 + 1;   //个位数为7且为7的倍数(从7开始,每70个一个),这些数重复计数了,需要减去
       printf("%d\n", c);
       return 0;
    }
    

    以上代码是如何实现的,请读者细品!

总结反思

用C语言解决问题,要从一开始想到的算法去一步一步优化。
比如本题中一开始的循环虽然可以解决问题,但是循环次数过多,能否减少循环次数呢,加快运行速度呢?
有时候也要换一个角度思考问题,比如本题最后一个方法就没有采用循环,事实上,更加加快运行速度。

C语言的特点是语法简单,程序执行效率高,适合用于嵌入式/底层开发,这就要求我们一定要注意算法的优化,加快运行效率!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值