跳转至

while 循环的应用02-数位与回文

下面的数位拆分、反转和回文例子,都先处理 0 <= n <= 10^9 的整数。

数位拆分

两个关键动作

x % 10 取出个位,x /= 10 去掉个位,拆出来的顺序是从右往左。

例如 x = 3042:

当前 x 取出的数字 去掉个位后
3042 2 304
304 4 30
30 0 3
3 3 0

中间的 0 也是一位,不能跳过。

求位数和数位和

#include <iostream>

using namespace std;

int main() {
    long long n;
    cin >> n;

    long long x = n; // 拆副本,保留原数
    int cnt = 0, sum = 0;
    if (x == 0) {
        cnt = 1; // 0也是一位数
    }
    while (x) {
        cnt++;
        sum += x % 10;
        x /= 10;
    }
    cout << cnt << ' ' << sum;

    return 0;
}

输入 3042,输出 4 9;输入 0,输出 1 0。

注意 0。 while (x) 在 x 为 0 时不执行,所以求位数要单独处理。

注意保留原数。 拆完以后 x 变成 0,后面还要用原数,就用副本来拆。

什么时候需要循环?

要做的事 写法
只取个位 n % 10,不用循环
拆一个三位数 直接算百、十、个位,不用循环
位数不固定,处理每一位 用 while 拆到结束
输入 n 个数,每个都拆数位 外层 for 读数,内层 while 拆数位

for 也能拆数位,先用自己看得清楚的写法。

反转一个整数

每取出一位,把新数乘 10,再把这一位加上去。

long long x = n, t = 0;
while (x) {
    t = t * 10 + x % 10;
    x /= 10;
}
cout << t;

123 拆出 3、2、1,t 依次变成 3、32、321。

输入 1200,输出 21。整数不会保留前导零,不能输出成 0021。

输入 0,循环不执行,t 保持为 0,结果也正确。

反转后可能比原数大,所以这里用 long long。数有几十位时,要改用字符串处理。

数字替换

B4496 [GESP202603 一级] 数字替换

把数中的 4 全都替换成 8。原题范围是 0 <= a <= 100000000。

#include <iostream>

using namespace std;

int main() {
    long long a, b = 0, t = 1;
    cin >> a;

    while (a) {
        int x = a % 10;
        if (x == 4) {
            x = 8;
        }
        b += x * t;
        a /= 10;
        t *= 10;
    }
    cout << b;

    return 0;
}

t 是位权,依次是 1、10、100……,把替换后的数字放回对应位置。

输入 0 时,不进入循环,b 保持为 0,结果也正确。

回文判断

正着读、反着读都一样,叫作回文。

121、1221、7 是回文,123、120 不是。这里把 0 也看作回文,不处理负数。

反转后,与原数比较

long long x = n, t = 0;
while (x) {
    t = t * 10 + x % 10;
    x /= 10;
}
if (t == n) {
    cout << "Yes";
}
else {
    cout << "No";
}

原数 n 要保留,不能拆完再拿 t 与已经变成 0 的 x 比较。

字符串判断(先不看)

学过字符串,再回来看。把左右两端的字符,一对一对比较。

#include <iostream>
#include <string>

using namespace std;

int main() {
    string s;
    cin >> s; // 输入一个非空数字串,长度不超过100000

    int l = 0, r = (int)s.size() - 1;
    bool flag = true;
    while (l < r) {
        if (s[l] != s[r]) {
            flag = false;
        }
        l++;
        r--;
    }
    if (flag) {
        cout << "Yes";
    }
    else {
        cout << "No";
    }

    return 0;
}

只要发现一对不同的字符,就不是回文;两端都检查完,才能确定是回文。

数字串 010 是回文。如果当作十进制整数读入,得到 10,就不是回文。看清题目比较的是什么。

二进制回文

一个整数,十进制不是回文,二进制也可能是。比如 21,二进制是 10101。

这里使用不补前导零的二进制写法,0 也看作回文。

换成二进制拆位,再反转比较。

十进制用 % 10、/= 10,二进制就用 % 2、/= 2。

long long x = n, t = 0;
while (x) {
    t = t * 2 + x % 2;
    x /= 2;
}
if (t == n) {
    cout << "Yes";
}
else {
    cout << "No";
}

这里的 t,保存的是反转二进制数位后的数值,不是把一串 0、1 当作十进制数存起来。

n 二进制写法 结果
0 0 Yes
5 101 Yes
6 110 No
9 1001 Yes
21 10101 Yes

不熟悉进制转换,可以先看二进制。