2 条题解

  • 2
    @ 2025-12-14 11:40:20

    一、思路分析(超详细)

    1. 题目核心:删除操作的本质拆解

    题目允许多次删除任意一对相邻且不同的字符,目标是求删除后字符串的最小长度。首先明确该删除操作的核心特征:

    • 操作本质:“消耗”两个不同字符(无论初始位置是否相邻)。即使两个不同字符不相邻,可通过删除中间字符让它们相邻,最终完成配对删除(例如字符串abc,可先删abc,或先删bca)。
    • 操作限制:无法删除相邻且相同的字符,因此“相同字符的出现次数”是决定最小长度的核心因素。

    2. 核心规律推导

    设字符串总长度为len,统计每个字符的出现次数,记出现次数最多的字符次数为max_cnt,其余所有字符的总次数为other_cnt = len - max_cnt。根据两者的关系,分两种情况推导最小长度:

    • 情况1:若max_cnt > other_cnt,说明出现次数最多的字符无法被其他字符完全配对消耗,最终剩余的字符数量为max_cnt - other_cnt(等价于2*max_cnt - len)。例如字符串abacaa出现3次,bc各出现1次,max_cnt=3other_cnt=2,3>2,最终剩余3-2=1个字符。
    • 情况2:若max_cnt ≤ other_cnt,说明所有字符可尽可能两两配对(不同字符),最终剩余的长度由字符串总长度的奇偶性决定:总长度为偶数则剩余0,奇数则剩余1(即len % 2)。例如字符串aabc总长度4(偶数),a出现2次,bc各1次,max_cnt=2other_cnt=2,2≤2,最终剩余0;字符串abcdefg总长度7(奇数),每个字符各出现1次,max_cnt=1other_cnt=6,1≤6,最终剩余1。

    3. 解题步骤(O(n) 时间复杂度)

    1. 输入处理:读取测试用例组数G,依次处理每组的字符串;
    2. 字符计数:遍历字符串,统计每个小写字母的出现次数;
    3. 关键值计算:找到出现次数最多的字符的次数max_cnt,并记录字符串总长度len
    4. 结果计算:根据max_cntother_cnt的关系,按上述两种情况计算最小长度;
    5. 输出结果:输出每组字符串对应的最小长度。

    二、带详细注释的C++代码

    #include<bits/stdc++.h>
    using namespace std;
    
    int main() {
        // 定义变量存储测试用例组数(题目中用G表示)
        int test_num;
        cin >> test_num;
        
        // 循环处理每组测试用例
        while (test_num--) {
            // 存储当前待处理的字符串
            string s;
            cin >> s;
            
            // 定义计数数组:char_count[0]对应'a',char_count[1]对应'b'…char_count[25]对应'z',初始值全为0
            int char_count[26] = {0};
            // 记录字符串的总长度
            int len = s.size();
            
            // 遍历字符串,统计每个字符的出现次数
            for (char c : s) {
                // 将字符转换为0-25的索引(如'a'-'a'=0,'z'-'a'=25),对应计数数组位置+1
                char_count[c - 'a']++;
            }
            
            // 找到所有字符中出现次数最多的那个次数max_cnt
            int max_cnt = 0;
            for (int i = 0; i < 26; i++) {
                max_cnt = max(max_cnt, char_count[i]);
            }
            
            // 计算删除操作后能得到的最小长度
            int min_length;
            if (max_cnt > len - max_cnt) {
                // 情况1:最多的字符数超过其他字符总和,剩余数量为2*max_cnt - len
                min_length = 2 * max_cnt - len;
            } else {
                // 情况2:最多的字符数不超过其他字符总和,剩余长度为总长度的奇偶性(偶数0,奇数1)
                min_length = len % 2;
            }
            
            // 输出当前字符串的最小长度
            cout << min_length << endl;
        }
        
        return 0;
    }
    

    三、代码关键细节补充

    1. 核心逻辑优化说明

    • 计数数组设计:仅使用长度为26的数组char_count,精准对应26个小写字母,无冗余空间;
    • 最大次数查找:直接遍历计数数组(仅26次循环),相比排序操作(如sort)更高效,避免了排序带来的额外时间开销;
    • 数据类型选择:全程使用int类型即可满足需求,因为字符串长度不超过10000,字符出现次数也不会超过该值,不存在整数溢出风险,无需额外定义long long

    2. 样例验证(文字版)

    逐一验证题目给出的样例输入,确保逻辑正确性:

    1. 样例输入aabc:字符串长度4,a出现2次,bc各出现1次。max_cnt=2other_cnt=2,满足max_cnt ≤ other_cnt,最小长度为4%2=0,与样例输出一致;
    2. 样例输入abaca:字符串长度5,a出现3次,bc各出现1次。max_cnt=3other_cnt=2,满足max_cnt > other_cnt,最小长度为2*3-5=1,与样例输出一致;
    3. 样例输入avbvvcvvvd:字符串长度10,v出现6次,abcd各出现1次。max_cnt=6other_cnt=4,满足max_cnt > other_cnt,最小长度为2*6-10=2,与样例输出一致;
    4. 样例输入abcdefg:字符串长度7,每个字符各出现1次。max_cnt=1other_cnt=6,满足max_cnt ≤ other_cnt,最小长度为7%2=1,与样例输出一致;
    5. 样例输入dabbb:字符串长度5,b出现3次,da各出现1次。max_cnt=3other_cnt=2,满足max_cnt > other_cnt,最小长度为2*3-5=1,与样例输出一致。

    3. 边界情况验证(文字版)

    针对特殊边界场景验证逻辑正确性:

    1. 全相同字符场景(如aaaaa):字符串长度5,a出现5次,max_cnt=5other_cnt=0,满足max_cnt > other_cnt,最小长度为2*5-5=5,符合预期(无法删除任何字符);
    2. 长度为1的字符串(如a):字符串长度1,a出现1次,max_cnt=1other_cnt=0,满足max_cnt > other_cnt,最小长度为2*1-1=1,符合预期(无字符可删除);
    3. 长度为2且字符不同的字符串(如ab):字符串长度2,ab各出现1次,max_cnt=1other_cnt=1,满足max_cnt ≤ other_cnt,最小长度为2%2=0,符合预期(可删除这对不同字符)。

    4. 时间与空间复杂度分析

    • 时间复杂度:每组测试用例的操作包括遍历字符串统计字符(O(n),n为字符串长度)、遍历计数数组找最大次数(O(26)),总时间复杂度为O(G*n)。其中G≤5n≤10000,该复杂度完全满足题目要求,运行效率极高;
    • 空间复杂度:仅使用固定大小的计数数组(26个int)和存储字符串的空间,空间复杂度为O(n)(主要由字符串存储占用),无额外冗余空间开销。

    信息

    ID
    4006
    时间
    1000ms
    内存
    128MiB
    难度
    6
    标签
    (无)
    递交数
    78
    已通过
    26
    上传者