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,再把这一位加上去。
123 拆出 3、2、1,t 依次变成 3、32、321。
输入 1200,输出 21。整数不会保留前导零,不能输出成 0021。
输入 0,循环不执行,t 保持为 0,结果也正确。
反转后可能比原数大,所以这里用 long long。数有几十位时,要改用字符串处理。
数字替换¶
把数中的 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 |
不熟悉进制转换,可以先看二进制。