Day05 2023/01/12
难度:简单
题目
实现删除字符串中出现次数最少的字符,若出现次数最少的字符有多个,则把出现次数最少的字符都删除。输出删除这些单词后的字符串,字符串中其它字符保持原来的顺序。数据范围:输入的字符串长度满足:1 ≤n≤ 20。
输入描述:
字符串只包含小写英文字母, 不考虑非法输入,输入的字符串长度小于等于20个字节。
输出描述:
删除字符串中出现次数最少的字符后的字符串。
示例
输入:aabcddd
输出:aaddd
思路
该题比较简单,因为题目要求字符串字符只能是小写英文字母,所以只需要维护一个大小为 26 的数组,该数组用来存储 每个字符出现的次数(通过遍历即可实现),在找到该数组中最小的元素 min(即出现次数最少元素所出现的次数为多少),接着遍历数组,如果当前字符出现的个数大于 min ,则输出,反之跳过。如图所示:
关键点
-
理解字符是如何转换成数组下标,本质是通过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;
}
- 时间复杂度 --- 一共平行遍历三次,大约循环了 3n 次 n 为字符串长度。
- 空间复杂度 --- 就一个固定大小26的辅助数组,属于常数级。
总结
-
关于字符串反转,计数相关的问题,都可以考虑使用辅助数组的方式解题。
-
这里除了要注意 字符是如何转换成数组下标 的,还要额外注意
min的初始值,因为传统求数组最小值时,min初始值为数组第一个元素(担心有些同学这里有惯性思维),但这里min为 字符串 第一个元素所出现的次数,并不是 数组 第一个元素。 -
例如:输入字符串为:
"ccbffd",如果这种情况下令min初值为数组第一个元素,就有问题,因为字符串中并没有字符'a',意味这统计数组中第一个元素里面是没有值的。