1.给定字符串的字符去重问题
问题描述
给定一个字符串 ss,你需要通过删除一些字符,使得每个字符在字符串中出现的次数均不相同。你需要找出最少需要删除的字符数量以达到这个目标。
例如,对于字符串 "aab",字符 "a" 出现2次,字符 "b" 出现1次,这些出现次数已经不同,因此不需要删除任何字符,输出为0。
测试样例
样例1:
输入:
s = "aab"
输出:0
样例2:
输入:
s = "aaabbbcc"
输出:2
样例3:
输入:
s = "abcdef"
输出:5
2.解题思路
这道题的核心是确保每个字符在字符串中的出现次数是唯一的。需要通过删除最少的字符,使得字符串中每个字符的出现次数都不相同。具体解题步骤如下:
1. 统计字符的出现次数
首先,需要统计字符串中每个字符出现的频率。可以使用哈希表(Map)来保存字符和对应出现次数的映射。
2. 处理重复的频率
接下来,需要处理出现次数重复的情况。因为目标是让每个字符的出现次数都不同,所以如果有字符的出现次数相同,则必须减少其中一个字符的出现次数,直到其出现次数不再重复。
3. 删除字符的次数计算
每次减少一个字符的出现次数,实际上是删除了该字符。并且需要记录每次减少出现次数的操作,最终得到最少需要删除的字符数量。
4. 使用 Set 防止重复次数
为了有效地判断某个出现次数是否已经被使用过,可以使用一个 Set 来存储已经出现过的频率。对于每个频率,如果它已经在 Set 中,则需要不断减少该频率,直到它变成一个尚未出现过的频率。
步骤
-
统计每个字符的出现次数:
- 使用一个哈希表来存储每个字符的出现次数。
-
使用 Set 跟踪出现次数:
- 对于每个出现次数,检查它是否已经出现过。如果出现过,则需要删除字符,直到这个出现次数不再重复。
-
计算最少删除的字符数量:
- 每次减少出现次数的操作,相当于删除一个字符。记录这些删除操作的次数,最后返回这个值。
3.代码实现
import java.util.*;
public class Main {
public static int solution(String s) {
// 统计每个字符出现的次数
Map<Character, Integer> freqMap = new HashMap<>();
for (char c : s.toCharArray()) {
freqMap.put(c, freqMap.getOrDefault(c, 0) + 1);
}
// 用一个 Set 来记录已经出现过的次数
Set<Integer> usedFreq = new HashSet<>();
int deleteCount = 0;
// 遍历频率列表,处理重复的频率
for (int count : freqMap.values()) {
while (count > 0 && usedFreq.contains(count)) {
// 如果该次数已经被使用,则减少次数
count--;
deleteCount++;
}
// 将新的次数加入到 usedFreq 中
if (count > 0) {
usedFreq.add(count);
}
}
return deleteCount;
}
public static void main(String[] args) {
System.out.println(solution("aab") == 0); // 不需要删除任何字符
System.out.println(solution("aaabbbcc") == 2); // 删除2个字符
System.out.println(solution("abcdef") == 5); // 删除5个字符
}
}
4.复杂度分析
-
时间复杂度:
- 统计字符频率的时间复杂度是 O(n),其中 n 是字符串的长度。
- 遍历频率并处理重复次数的时间复杂度是 O(k),其中 k 是字符种类的数量(最多为 26,对于英文字符)。
- 总体时间复杂度为 O(n + k),其中 n 是字符串长度,k 是字符种类的数量。
-
空间复杂度:
- 使用一个哈希表来存储字符的频率,空间复杂度为 O(k)。
- 使用一个 Set 来存储出现次数,空间复杂度为 O(k)。
- 总体空间复杂度为 O(k),其中 k 是字符种类的数量。