小改的一些话

人无完人,我只是一位C++的初学者,并不是一位专业的C++软件工程师,如果本篇文章有一些细微的错误或者是您有什么好的方法也希望您可以在本文下面评论,我会认真阅读并考虑采纳的。

题目内容

题目链接:http://noi.openjudge.cn/ch0103/20/

内容:给定非负整数n,求2n

题目就是这么简单,是个人都知道怎么做:

// The Simple Code
#include <bits/stdc++.h>
using namespace std;

int main() {
    unsigned int num, power;
    scanf("%d", &power);
    num = (int) pow(2, power);
    printf("%d", num);
    return 0;
}

提交一下看下:

OK,AC了,本篇文章结束(了吗?)

思路整理

虽然本篇文章的确就是讲这个题,但这不代表这道题就这么水灵灵的解完了。

要知道,我们即便不用pow()函数,我们也可以利用for,if亦或者while来解这题,方法又不是只有这一个。

不难注意到,指数是非负数,我们就无需考虑负数的情况(这里便于理解就用了无符号整型,大家也懂)

那么当底数不为零的时候,指数一般有以下三种情况(此处只谈指数的非负整数情况):

1.指数为零,结果为1;

2.指数为一,结果为其本身;

3.指数每加一,就多乘他本身。

假定他数值的本身为2,那么我们就可以写个if分支语句来判断是否等于0的情况,然后继续累乘即可。

那么我们可以简单粗略的写一下他的代码:

// The First Wrong Answer
#include <bits/stdc++.h>
using namespace std;

int main() {
    unsigned int power = 0, num = 2;
    scanf("%d", &power);
    // 讨论指数的情况
    if (power == 0) {
        num = 1;
    } else {
        for (int i = 0; i <= power; ++i) {
            num *= 2;
        }
    }
    cout << num;
    return 0;
}

提交一下:

和小改猜的没错,Wrong Answer。

这题很显然我们踩了一个坑,你与power取等,也就是说取等了那条件也是真啊,很显然这就多执行了一次,所以我们把小于等于改小于号试试:

// The Second Wrong Answer
#include <bits/stdc++.h>
using namespace std;

int main() {
    unsigned int power = 0, num = 2;
    scanf("%d", &power);
    if (power == 0) {
        num = 1;
    } else {
        for (int i = 0; i < power; ++i) {
            num *= 2;
        }
    }
    cout << num;
    return 0;
}

小改改完之后再提交一遍看:

"人家Wrong Answer只是想跟主人一起贴贴而已哪有什么坏心思嘛"

这里其实改成小于后也是错的,很显然,你i为0,后面运行完一遍这个循环体后才自增,那么运行这个程序还要多自乘一个2,也就是实际上你计算的是2的(power + 1)次方。

改这个bug很简单,i的初始值改成1,或者是i小于(power - 1)都能解决。

// The Code Before Changing
#include <bits/stdc++.h>
using namespace std;

int main() {
    unsigned int power = 0, num = 2;
    scanf("%d", &power);
    if (power == 0) {
        num = 1;
    } else {
        for (int i = 1; i < power; ++i) {
            num = num * 2;
        }
    }
    cout << num;
    return 0;
}

清一色的AC就是看着舒服,很显然bug修复了,要求也达到了。

优化代码

对,上述程序我们成功用了一个不同的思路来做了这个程序。

但是!你不觉得这个诗(史)山看着很不爽吗?为什么我还要个if分支判断power是否为0啊,我不能直接令num的初始值为1吗,他power为0我就跳过for循环不行吗?

很显然,我们可以改成这样:

// The Final Code
#include <bits/stdc++.h>
using namespace std;

int main() {
    unsigned int power = 0, num = 1;
    scanf("%d", &power);
    for (int i = 0; i < power && power != 0; ++i) {
        num = num * 2;
    }
    cout << num;
    return 0;
}

这看着不舒服吗?这不简洁吗?虽然不如直接用pow()函数,但起码不需要你的条件分支就可以解决这个问题,这样不很好吗?

提交一下:

程序肯定是没什么大问题的,所以AC也很自然。

整体程序看着就是舒服,思路清晰,这总比写分支好吧。(虽然内存多占用了几kb)

总结

通过这一次的刷题,我也大致知道了一题不止有一个解。

在平时的学习中,我们也需要掌握一个程序其他的实现方法。

当然,在本次学习中,给我了一个收获就是:我的排查错误能力得到了较大的提升。

那么这篇文章到此也为之了,感兴趣的小伙伴也可以尝试用其他方法去解这道题。