跳转至

数学逻辑

一、拆解整数(提取各位数字)

这是最基础的操作。核心口诀:取末位用 % 10,扔掉末位用 / 10。

1. 提取固定位数(比如三位数)

1
2
3
4
int n = 248;
int ge  = n % 10;          // 个位:8
int shi = n / 10 % 10;     // 十位:4
int bai = n / 100 % 10;    // 百位:2

2. 通用提取(利用 while 循环,适合任意位数)

1
2
3
4
5
6
int n = 12345;
while (n > 0) {
    int digit = n % 10;   // 拿到当前最低位
    cout << digit << " "; // 输出:5 4 3 2 1(倒序输出)
    n /= 10;              // 扔掉最低位
}

二、构造整数(正序与倒序)

这在之前的 248 题里你已经用过了,这是初学者最容易搞混的地方。核心口诀:倒序拼凑用乘法 * 10 +,正序拼凑用权重 * power。

1. 整数倒序(最常用)

1
2
3
4
5
6
int n = 12345, rev = 0;
while (n > 0) {
    rev = rev * 10 + n % 10; // 先出来的个位,不断被推到最高位
    n /= 10;
}
// rev 最终为 54321

2. 整数正序(配合权重)

1
2
3
4
5
6
7
int n = 12345, res = 0, power = 1;
while (n > 0) {
    res = res + (n % 10) * power; // 个位乘1,十位乘10...
    power *= 10;
    n /= 10;
}
// res 最终为 12345

3. 字符串拼接法(适合不做数学运算,只做展示)

1
2
3
string s = to_string(12345);
reverse(s.begin(), s.end()); // 需要包含 <algorithm> 头文件
int rev = stoi(s); // 转回整数

三、整数基本属性(位数、求和、回文)

基于前面的逻辑,衍生出的常见题型。

1. 求一个整数是几位数

1
2
3
4
5
6
int n = 12345, count = 0;
while (n > 0) {
    count++;
    n /= 10;
}
// count 为 5

2. 求各位数字之和

1
2
3
4
5
6
int n = 12345, sum = 0;
while (n > 0) {
    sum += n % 10; // 累加每一位
    n /= 10;
}
// sum 为 15

3. 判断回文数(正着读和倒着读一样)

1
2
3
4
5
6
int n = 12321, temp = n, rev = 0;
while (temp > 0) {
    rev = rev * 10 + temp % 10;
    temp /= 10;
}
if (rev == n) cout << "是回文数"; // 成立

四、基础数论(编程题常客)

1. 求最大公约数(辗转相除法 / 欧几里得算法)

1
2
3
4
5
6
7
int a = 24, b = 36;
while (b != 0) {
    int temp = b;
    b = a % b;
    a = temp;
}
// a 最终为 12(最大公约数)

2. 求最小公倍数

// 公式:a * b / 最大公约数
int lcm = 24 * 36 / 12; // 结果为 72

_注意:实际写代码时,建议先除后乘,防止溢出:a / gcd _ b。*

3. 判断质数(素数)

1
2
3
4
5
6
7
bool isPrime(int n) {
    if (n <= 1) return false;
    for (int i = 2; i * i <= n; i++) { // i * i 是核心优化
        if (n % i == 0) return false;
    }
    return true;
}

4. 冒泡排序

#include <iostream>
using namespace std;

int main() {
    int arr[] = {5, 2, 9, 1, 5, 6};
    int n = sizeof(arr) / sizeof(arr[0]); // 自动计算数组长度

    // 外层循环:控制比较的轮数,一共需要 n-1 轮
    for (int i = 0; i < n - 1; i++) {

        // 内层循环:控制每一轮的比较次数
        // 每过一轮,就会有一个最大的数被排到末尾,所以比较次数要减去 i
        for (int j = 0; j < n - 1 - i; j++) {

            // 如果前一个数比后一个数大,就交换它们(升序)
            if (arr[j] > arr[j + 1]) {
                int temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }

    // 输出排序后的结果
    cout << "排序后:";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;

    return 0;
}

五、浮点数与取整(需要 <cmath> 头文件)

C++ 中整数除法 / 是直接截断(丢弃小数),比如 3 / 2 = 1。

函数 含义 示例
floor(x) 向下取整 floor(2.9) → 2.0
ceil(x) 向上取整 ceil(2.1) → 3.0
round(x) 四舍五入 round(2.5) → 3.0
(int)x 强制截断 (int)2.9 → 2
abs(x) 绝对值 abs(-5) → 5(整数)或 fabs(-5.5)(浮点数)

⚠️ 初学者大坑: 7 / 2 = 3(整数除法),但 7.0 / 2 = 3.5。 想要得到精确小数,至少要把其中一个操作数写成小数:7.0 / 2 或 (double)7 / 2。

六、通用进制转换(短除法)

这是你之前 248 题用到的核心逻辑。十进制转其他进制(如七进制、九进制、二进制),万能模板:

int n = 248;
int base = 7; // 目标进制
int res = 0, power = 1; // 如果转成数字
string s = "";          // 如果转成字符串展示

while (n > 0) {
    int digit = n % base; // 取余数
    res = res + digit * power; // 正序拼凑
    power *= 10;
    s = char(digit + '0') + s; // 字符串拼接(倒序插入)
    n /= base;
}

字符逻辑

// 字符串转大写(const 引用 + 返回值)

string toUpper(const string &s)
{
string result = s;
for (char &c : result)
{
if (c >= 'a' && c <= 'z')
{
c = c - 'a' + 'A';
}
}
return result;
}

// 反转字符串

1
2
3
4
5
6
7
8
9
string reverseString(const string &s)
{
string result;
for (int i = (int)s.size() - 1; i >= 0; i--)
{
result += s[i];
}
return result;
}

💡 给初学者的 3 个建议:

  1. 优先用 while(n > 0) 循环处理整数,这比用 for 循环硬算位数灵活得多。
  2. % 和 / 是黄金搭档,几乎所有整数拆解问题都靠它们。
  3. 多画图、多手动模拟。遇到卡壳的逻辑,拿一张纸,把 n 和 res 的变化过程一行行写出来,瞬间就能看懂。

把这些模板吃透,以后遇到“水仙花数”、“回文数”、“进制转换”、“数位统计”这类题,你就能直接秒杀了。加油!