HJ23 删除字符串中出现次数最少的字符

343 阅读3分钟

Day05 2023/01/12

题目链接

难度:简单

题目

实现删除字符串中出现次数最少的字符,若出现次数最少的字符有多个,则把出现次数最少的字符都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。数据范围:输入的字符串长度满足:1 ≤n≤ 20。

输入描述:

字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。

输出描述:

删除字符串中出现次数最少的字符后的字符串。

示例

输入:aabcddd
输出:aaddd

思路


该题比较简单,因为题目要求字符串字符只能是小写英文字母,所以只需要维护一个大小为 26 的数组,该数组用来存储 每个字符出现的次数(通过遍历即可实现),在找到该数组中最小的元素 min即出现次数最少元素所出现的次数为多少),接着遍历数组,如果当前字符出现的个数大于 min ,则输出,反之跳过。如图所示: D5EF2862C00A21BBFC433ECCC33C4476.gif

关键点


  • 理解字符是如何转换成数组下标,本质是通过ASCII 码所对应的十进制数相减而得来的。、

  • 例如:第一个字符为 'a' ,则 'a' - 'a' 就转换成了数组下标 0 ,第二个字符为 'c' ,则 'c'-'a' 就转换成了数组下标 2

  • 初始时,min为 字符串 第一个元素所出现的次数,但并不是 数组 第一个元素,千万要理解

算法实现


c++代码实现-使用辅助数组

#include <iostream>
#include <string>
#include <vector>

using namespace std;

// 方法:通过一个辅助数组,记录字符出现次数
int main() {
    string str; //输入的字符串
    vector<int> cal(26, 0); //统计数组大小26,初始时每个元素为0
    int min; //待删除字符出现的次数
    cout << "请输入目标字符串:";   
    getline(cin, str); //获取整行字符串
    
    //循环统计字符串中每个字符出现的次数
    for(int i = 0; i < str.length(); i++) {    
        cal[str[i] - 'a']++; //这里减a,是为了把字母的ascii码改为数组下标
    }

    //找出出现次数最小的字符出现的次数
    min = cal[str[0] - 'a']; //初始时,min为字符串第一个元素所出现的次数
    for(int j = 1; j < cal.size(); j++) {
        if(cal[j] < min && cal[j > 0]) min = cal[j];
    }

    //循环输出出现次数大于min的字符
    cout << "删除字符串中出现次数最少的字符后的字符串: ";
    for(int k = 0; k < str.length(); k++) { //这里循环出口为字符串长度,是因为我们输出的是字符串,而不是数组中记录的字符出现的次数
        if(cal[str[k] - 'a'] > min) cout << str[k] << " ";  
    }

    return 0;
}
  • 时间复杂度 O(n)O(n) --- 一共平行遍历三次,大约循环了 3nn 为字符串长度。
  • 空间复杂度 O(1)O(1)--- 就一个固定大小26的辅助数组,属于常数级。

总结

  • 关于字符串反转,计数相关的问题,都可以考虑使用辅助数组的方式解题。

  • 这里除了要注意 字符是如何转换成数组下标 的,还要额外注意 min 的初始值,因为传统求数组最小值时,min 初始值为数组第一个元素(担心有些同学这里有惯性思维),但这里 min字符串 第一个元素所出现的次数,并不是 数组 第一个元素。

  • 例如:输入字符串为:"ccbffd" ,如果这种情况下令 min 初值为数组第一个元素,就有问题,因为字符串中并没有字符 'a',意味这统计数组中第一个元素里面是没有值的。