
1. 问题概述与目标
在字符串处理中,我们经常需要对字符串进行去重操作,即移除字符串中重复出现的字符,只保留每个字符的第一次出现。在此基础上,有时还需要比较不同字符串之间的字符集合,例如计算一个字符串中包含另一个字符串的多少个唯一字符。
本教程的目标是解决以下具体问题:
- 给定一个主字符串 B 和一个字符串数组 a。
- 对主字符串 B 进行字符去重。
- 对数组 a 中的每个字符串也进行字符去重。
- 对于数组 a 中去重后的每一个字符串,计算它与去重后的主字符串 B 之间共享的唯一字符数量。
- 将这些计数结果按原数组顺序存储在一个整数数组中返回。
例如,如果 B = "iyee" 和 a = ["hi", "bye", "bebe"]:
- 去重后的 B 为 "iye"。
- 去重后的 a 为 ["hi", "bye", "be"]。
- 对于 "hi":其中字符 'i' 存在于 "iye" 中,计数为 1。
- 对于 "bye":其中字符 'y', 'e' 存在于 "iye" 中,计数为 2。
- 对于 "be":其中字符 'e' 存在于 "iye" 中,计数为 1。
- 最终输出应为 [1, 2, 1]。
2. 核心逻辑实现
为了高效地解决上述问题,我们将采用模块化的方法,将字符串去重逻辑封装为一个独立的辅助函数,然后主函数负责协调去重和计数过程。
2.1 字符串去重辅助函数
字符串去重是本问题的基础。一个高效的去重方法是使用 HashSet 来跟踪已经遇到的字符。HashSet 提供了 O(1) 的平均时间复杂度来检查元素是否存在和添加元素,这使得它非常适合用于去重。
10分钟内自己学会PHP其中,第1篇为入门篇,主要包括了解PHP、PHP开发环境搭建、PHP开发基础、PHP流程控制语句、函数、字符串操作、正则表达式、PHP数组、PHP与Web页面交互、日期和时间等内容;第2篇为提高篇,主要包括MySQL数据库设计、PHP操作MySQL数据库、Cookie和Session、图形图像处理技术、文件和目录处理技术、面向对象、PDO数据库抽象层、程序调试与错误处理、A
import java.util.HashSet;
import java.util.Set;
import java.lang.StringBuilder; // 导入StringBuilder
public class StringProcessor {
/**
* 对输入字符串进行字符去重,返回只包含唯一字符的新字符串。
* 字符的顺序将保持其首次出现的顺序。
*
* @param s 待去重的字符串。
* @return 去重后的字符串。
*/
public static String dist(String s) {
StringBuilder sb = new StringBuilder();
Set set = new HashSet<>(); // 使用HashSet存储已遇到的字符
for (int i = 0; i < s.length(); i++) {
char currentChar = s.charAt(i);
// 如果HashSet中不包含当前字符,则添加并将其追加到StringBuilder
if (set.add(currentChar)) { // set.add() 返回 true 如果元素是新加入的
sb.append(currentChar);
}
}
return sb.toString();
}
// ... 主函数 mathProfessor 将在此处添加
} 代码解析:
- dist(String s) 函数接收一个字符串作为输入。
- StringBuilder sb 用于构建去重后的字符串,因为它在循环中追加字符比 String 的拼接操作更高效。
- Set
set = new HashSet(); 用于存储已经添加到 sb 中的字符。HashSet 的 add() 方法在添加元素时会返回一个布尔值:如果元素是新加入的(即之前不存在),则返回 true;如果元素已经存在,则返回 false。我们利用这个特性来判断字符是否是唯一的。 - 遍历输入字符串 s 的每个字符,如果 set.add(currentChar) 返回 true,说明这是一个新字符,将其追加到 StringBuilder 中。
2.2 主处理函数
主函数 mathProfessor 将利用 dist 辅助函数来完成整个任务流程。
import java.util.Arrays; // 导入Arrays工具类
public class StringProcessor {
// ... dist 方法在此处
/**
* 根据给定规则处理主字符串和字符串数组。
* 规则包括:对主字符串和数组中每个字符串进行字符去重,
* 然后计算数组中每个去重后的字符串与去重后的主字符串共享的唯一字符数量。
*
* @param b 主字符串。
* @param a 字符串数组。
* @return 一个整数数组,包含每个去重后的数组元素与去重后的主字符串共享的字符数量。
*/
static int[] mathProfessor(String b, String[] a) {
// 1. 对主字符串进行字符去重
b = dist(b);
// 2. 初始化结果存储数组
int[] countArr = new int[a.length];
// 临时存储去重后的数组元素
String[] distinctArrayElements = new String[a.length];
// 3. 对输入数组a中的每个字符串进行字符去重
for (int i = 0; i < a.length; i++) {
distinctArrayElements[i] = dist(a[i]);
}
// 4. 计算每个去重后的数组元素与去重后的主字符串共享的字符数量
for (int i = 0; i < distinctArrayElements.length; i++) {
int currentCount = 0; // 为每个数组元素重置计数器
String currentDistinctElement = distinctArrayElements[i];
// 遍历去重后的主字符串的每个字符
for (int j = 0; j < b.length(); j++) {
char charFromB = b.charAt(j);
// 检查主字符串的当前字符是否包含在去重后的数组元素中
if (currentDistinctElement.contains(Character.toString(charFromB))) {
currentCount++;
}
}
countArr[i] = currentCount; // 存储当前元素的计数
}
return countArr;
}
public static void main(String[] args) {
String mainString = "iyee";
String[] stringArray = {"hi", "bye", "bebe"};
int[] result = mathProfessor(mainString, stringArray);
System.out.println("示例输入: 主字符串=\"" + mainString + "\", 字符串数组=" + Arrays.toString(stringArray));
System.out.println("示例输出: " + Arrays.toString(result)); // 预期输出: [1, 2, 1]
String mainString2 = "apple";
String[] stringArray2 = {"banana", "orange", "pineapple"};
int[] result2 = mathProfessor(mainString2, stringArray2);
System.out.println("示例输入: 主字符串=\"" + mainString2 + "\", 字符串数组=" + Arrays.toString(stringArray2));
System.out.println("示例输出: " + Arrays.toString(result2)); // 预期输出: [2, 2, 3] ('a','p' for banana; 'a','e' for orange; 'a','p','e' for pineapple)
}
}代码解析:
- mathProfessor(String b, String[] a) 函数接收主字符串 b 和字符串数组 a。
- 首先调用 dist(b) 对主字符串进行去重,并将结果重新赋值给 b。
- 初始化 countArr 数组来存储最终的计数结果,其大小与输入数组 a 相同。
- 创建 distinctArrayElements 数组,用于存储 a 中每个字符串去重后的结果。
- 第一个 for 循环遍历输入数组 a,对每个元素调用 dist() 进行去重,并将结果存入 distinctArrayElements。
- 第二个 for 循环是核心计数逻辑:
- 它遍历 distinctArrayElements 中的每一个去重后的字符串。
- 内部循环遍历去重后的主字符串 b 的每一个字符。
- currentDistinctElement.contains(Character.toString(charFromB)) 检查主字符串的当前字符是否包含在 distinctArrayElements 的当前元素中。contains 方法在这里的效率足够,因为 distinctArrayElements 中的字符串通常不会很长。
- 如果包含,则 currentCount 增加。
- 完成内部循环后,currentCount 被存储到 countArr 中,并为下一个数组元素重置为 0。
- 最后返回 countArr。
3. 注意事项与性能优化
- 字符串去重效率: HashSet 在字符去重方面表现出色,其平均时间复杂度为 O(N),其中 N 是字符串的长度。相比于使用 String.chars().distinct().forEach() 这种基于流的操作,HashSet 的方法在某些场景下可能更直接且性能更优,尤其是在多次调用去重操作时。
-
字符集支持: 此实现适用于处理任何 Unicode 字符,因为 char 类型和 HashSet
能够正确处理它们。 -
空字符串或空数组:
- 如果输入的主字符串 b 为空字符串 "",则 dist(b) 返回 "",最终 countArr 中的所有计数都将为 0,这符合逻辑。
- 如果输入数组 a 为空数组,countArr 将是一个长度为 0 的数组,同样符合预期。
- 如果 a 中包含空字符串,dist("") 返回 "",该空字符串与任何字符的交集都为 0。
-
String.contains() 的性能: 在计算字符交集时,currentDistinctElement.contains(Character.toString(charFromB)) 的效率取决于 currentDistinctElement 的长度。对于较短的去重字符串,其性能开销可以忽略不计。如果 currentDistinctElement 长度非常大,并且需要进行大量这样的检查,可以考虑将 currentDistinctElement 也转换为 HashSet
以获得 O(1) 的平均查找时间。但在本场景下,由于去重后的字符串长度通常不会超过字符集大小(例如,对于英文字母只有26个),现有方法已经足够高效。
4. 总结
本教程提供了一个清晰且高效的解决方案,用于对主字符串和字符串数组进行字符去重,并计算它们之间的唯一字符交集。通过将字符串去重逻辑封装在 dist 辅助函数中,我们实现了代码的模块化和可重用性。HashSet 的使用确保了去重操作的高效性,而主函数则通过迭代和比较,准确地计算了所需的字符交集数量。这种方法不仅解决了特定问题,也展示了在处理字符串和字符集合时常用的高效编程实践。









