
在字符串处理中,我们经常需要对字符串进行去重操作,即提取其中所有不重复的字符。更进一步,当面对一个字符串数组时,可能需要对数组中的每个字符串都进行去重,然后将这些去重后的字符串与一个目标字符串(也经过去重处理)进行比较,统计每个数组元素与目标字符串有多少个共同的去重字符。
例如,给定一个目标字符串 "iyee" 和一个字符串数组 ["hi", "bye", "bebe"]:
字符串去重是本问题的基础。从一个字符串中提取所有不重复的字符,并按其首次出现的顺序组合成一个新的字符串。
HashSet 是Java集合框架中用于存储不重复元素的优秀工具。我们可以遍历字符串的每个字符,尝试将其添加到 HashSet 中。如果 add 方法返回 true,说明该字符是首次出现,我们将其追加到结果 StringBuilder 中。
立即学习“Java免费学习笔记(深入)”;
import java.util.HashSet;
import java.util.Set;
/**
* 从给定字符串中提取所有不重复的字符,并按其首次出现的顺序返回。
*
* @param s 待去重的字符串。
* @return 包含去重字符的新字符串。
*/
public static String dist(String s) {
StringBuilder sb = new StringBuilder();
Set<Character> set = new HashSet<>(); // 使用HashSet存储已遇到的字符
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// 如果字符首次添加到set中,则将其追加到结果字符串
if (set.add(c)) {
sb.append(c);
}
}
return sb.toString();
}优点: 这种方法逻辑清晰,效率较高(HashSet 的 add 操作平均时间复杂度为 O(1))。 注意事项: 这种方法保留了字符首次出现的顺序。
Java 8 引入的 Stream API 提供了另一种简洁的去重方式:
import java.util.stream.Collectors;
// ... (在同一个类中)
public static String distWithStream(String s) {
return s.chars() // 将字符串转换为IntStream,表示字符的ASCII值
.distinct() // 去除重复的字符
.mapToObj(c -> String.valueOf((char) c)) // 将int转换回char并包装为String
.collect(Collectors.joining()); // 将所有字符连接成一个字符串
}优点: 代码更简洁,更具函数式风格。 注意事项: distinct() 操作不保证保留原始字符的顺序。对于本问题,顺序不影响最终计数结果,因此两种 dist 方法均适用。通常,HashSet 的手动实现可能在性能上略优于 Stream 对于简单场景。在本教程中,我们将沿用 HashSet 的实现。
在拥有了 dist 方法后,我们可以轻松地对字符串数组中的每个元素进行去重处理。
// 假设我们有一个字符串数组 a
String[] a = {"hi", "bye", "bebe"};
String[] distinctArray = new String[a.length];
for (int i = 0; i < a.length; i++) {
distinctArray[i] = dist(a[i]); // 对数组中的每个字符串调用去重方法
}
// 此时 distinctArray 变为 ["hi", "bye", "be"]这是问题的核心部分。我们需要比较两个去重后的字符串,计算它们之间有多少个共同的字符。
/**
* 计算两个去重后的字符串有多少个共同字符。
*
* @param s1 第一个去重字符串。
* @param s2 第二个去重字符串。
* @return 共同字符的数量。
*/
public static int countCommonDistinctChars(String s1, String s2) {
int count = 0;
// 遍历其中一个字符串的每个字符
for (int i = 0; i < s1.length(); i++) {
char c = s1.charAt(i);
// 检查这个字符是否存在于另一个字符串中
if (s2.contains(String.valueOf(c))) {
count++;
}
}
return count;
}效率考量: String.contains() 方法在内部会进行线性搜索,其时间复杂度为 O(m),其中 m 是被搜索字符串的长度。如果 s1 和 s2 都非常长,且此操作需要频繁执行,可以考虑将其中一个字符串转换为 HashSet<Character> 以实现 O(1) 的平均查找时间。然而,对于大多数实际应用场景,当字符串长度不是极端大时,当前方法足够高效且易于理解。
将上述所有步骤整合到一个主方法中,即可得到完整的解决方案。
import java.util.HashSet;
import java.util.Set;
import java.util.Arrays; // 用于打印数组,方便测试
public class StringProcessor {
/**
* 从给定字符串中提取所有不重复的字符,并按其首次出现的顺序返回。
*
* @param s 待去重的字符串。
* @return 包含去重字符的新字符串。
*/
public static String dist(String s) {
StringBuilder sb = new StringBuilder();
Set<Character> set = new HashSet<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (set.add(c)) {
sb.append(c);
}
}
return sb.toString();
}
/**
* 根据指定逻辑处理字符串和字符串数组:
* 1. 对目标字符串 B 进行去重。
* 2. 对数组 a 中的每个字符串进行去重。
* 3. 计算去重后的数组元素与去重后的目标字符串 B 的共同字符数量。
*
* @param b 目标字符串。
* @param a 字符串数组。
* @return 一个整数数组,包含每个数组元素与目标字符串的共同字符数量。
*/
public static int[] mathProfessor(String b, String[] a) {
// 1. 对目标字符串 B 进行去重
String distinctB = dist(b);
// 2. 对数组 a 中的每个字符串进行去重,并存储到新数组中
String[] distinctArrayElements = new String[a.length];
for (int i = 0; i < a.length; i++) {
distinctArrayElements[i] = dist(a[i]);
}
// 3. 计算共同字符数量并存储结果
int[] countResult = new int[a.length];
for (int i = 0; i < distinctArrayElements.length; i++) {
int currentCount = 0;
String currentElement = distinctArrayElements[i];
// 遍历去重后的目标字符串 B 的每个字符
for (int j = 0; j < distinctB.length(); j++) {
char charFromB = distinctB.charAt(j);
// 检查当前字符是否存在于去重后的数组元素中
if (currentElement.contains(String.valueOf(charFromB))) {
currentCount++;
}
}
countResult[i] = currentCount;
}
return countResult;
}
public static void main(String[] args) {
String sampleB = "iyee";
String[] sampleA = {"hi", "bye", "bebe"};
int[] output = mathProfessor(sampleB, sampleA);
System.out.println("Sample Input B: \"" + sampleB + "\"");
System.out.println("Sample Input A: " + Arrays.toString(sampleA));
System.out.println("Sample Output: " + Arrays.toString(output)); // 预期输出: [1, 2, 1]
String sampleB2 = "programming";
String[] sampleA2 = {"java", "python", "javascript", "go"};
int[] output2 = mathProfessor(sampleB2, sampleA2);
System.out.println("\nSample Input B: \"" + sampleB2 + "\"");
System.out.println("Sample Input A: " + Arrays.toString(sampleA2));
System.out.println("Sample Output: " + Arrays.toString(output2));
// distinctB = "progami"
// distinctA2 = ["jav", "pytho", "javascrit", "go"]
// "jav" vs "progami" -> 'a' -> 1
// "pytho" vs "progami" -> 'p', 'o' -> 2
// "javascrit" vs "progami" -> 'a', 'r', 'g', 'i' -> 4
// "go" vs "progami" -> 'g', 'o' -> 2
// Expected: [1, 2, 4, 2]
}
}字符集支持: 当前的 char 类型和 String.contains() 方法能够很好地处理大多数Unicode字符。如果需要处理更复杂的Unicode码点(例如代理对),可能需要更细致的字符迭代方式(如 s.codePoints())。但对于常见场景,现有方法已足够。
性能优化:
// 优化后的计数逻辑示例
// ...
Set<Character> distinctBSet = new HashSet<>();
for (char c : distinctB.toCharArray()) {
distinctBSet.add(c);
}
for (int i = 0; i < distinctArrayElements.length; i++) {
int currentCount = 0;
String currentElement = distinctArrayElements[i];
Set<Character> currentElementSet = new HashSet<>();
for (char c : currentElement.toCharArray()) {
currentElementSet.add(c);
}
for (char charFromB : distinctBSet) { // 遍历Set,效率更高
if (currentElementSet.contains(charFromB)) { // Set查找平均O(1)
currentCount++;
}
}
countResult[i] = currentCount;
}
// ...这种优化在字符串长度较大时效果显著,但会增加内存开销。对于本例中的短字符串,原始方案的简洁性可能更具优势。
代码可读性: 将去重逻辑封装在独立的 dist 方法中,极大地提高了主方法的清晰度和模块化程度,是良好的编程实践。
本教程提供了一个在Java中处理字符串去重和字符匹配计数的完整解决方案。通过 HashSet 有效地实现了字符串去重,并结合循环和 String.contains() 方法完成了字符匹配计数。文章不仅提供了可运行的代码示例,还讨论了潜在的性能优化方向和注意事项,帮助读者在实际开发中灵活应用这些技术。掌握这些字符串处理技巧,将有助于更高效地解决各类文本数据分析和处理问题。
以上就是字符串去重与字符匹配计数:高效处理字符数组的Java教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号