问题分析 我们有很长的数字(比如175438) 需要删除4个数字,让剩下的数字组成最小的新数 目标:像玩拼图一样,去掉一些数字块,让剩下的数字最小

2️⃣ 贪心策略(关键思想) 核心规则:从数字的最高位(最左边)开始检查 找"山峰":寻找第一个比右边数字大的数字(比如175438中的7>5) 为什么要删"山峰"?因为高位数字越大,整个数就越大! 特殊情况:如果整个数字是递增的(如12345),就删除最后一位(最大的数字)

3️⃣ 执行步骤(以输入175438为例)

步骤 当前数字 操作说明 删除后结果

1 175438 发现7>5(山峰) 删除7 → 15438

2 15438 发现5>4(山峰) 删除5 → 1438

3 1438 发现4>3(山峰) 删除4 → 138

4 138 没有山峰,删除最后一位 删除8 → 13

4️⃣ 特殊处理技巧 前导零处理: 像00123要变成123 但要注意000要变成0(不能全删光) 代码中while循环跳过开头的零 边界情况: 如果删光所有数字?输出0 如果数字是100删1位?删第一个1变成00→处理成0

5️⃣ 为什么这个算法有效? 高位优先:数字的高位(左边)影响最大,优先让高位变小 及时止损:尽早删除让数字变大的"坏数字"(山峰) 贪心选择:每一步都做当前最优的选择(删一个让剩余数最小的数字)

💡 学习要点

字符串处理:用string处理长数字比用整数更方便

循环嵌套:外层控制删除次数,内层寻找要删除的位置

边界检查:特别注意字符串长度变化和越界问题

特殊处理:前导零和全零情况的处理技巧

#include <bits/stdc++.h>
using namespace std;
int main() {
    string n;  // 用字符串存储高精度数字(因为数字可能长达240位)
    int s;     // 需要删除的数字个数
    
    // 输入原始数字和要删除的数字个数
    cin >> n >> s;
    
    // 循环删除s个数字
    for (int k = 0; k < s; k++) {
        // 1. 从数字的最高位(字符串开头)开始检查
        // 2. 寻找第一个"山峰":即找到第一个比它右边数字大的数字
        int i = 0;
        while (i < n.length() - 1) {  // 确保不超出字符串范围
            // 当发现当前数字大于下一个数字时(形成下降趋势)
            if (n[i] > n[i + 1]) {
                break;  // 找到要删除的数字位置
            }
            i++;  // 继续检查下一位
        }
        
        // 删除找到的数字(要么是"山峰"数字,要么是最后一位)
        n.erase(i, 1);  // 从位置i删除1个字符
        
        // 特殊情况处理:如果删除后字符串变空,提前结束
        if (n.empty()) {
            break;
        }
    }
    
    // 处理前导零(但保留最后一位,即使它是0)
    int start = 0;  // 查找第一个非零位置
    while (start < n.length() - 1 && n[start] == '0') {
        start++;  // 跳过前导零
    }
    
    // 输出结果:从第一个非零位置开始到字符串结束
    // 特殊情况:如果所有数字都是0,输出0
    if (n.substr(start) == "") {
        cout << "0";
    } else {
        cout << n.substr(start);
    }
    
    return 0;
}

0 条评论

目前还没有评论...