在字符串中查找子串及字符匹配处理的技术问题求助
解决字符串处理的两个常见困扰:子串查找与字符匹配
嘿,我完全懂你碰到的这两个字符串问题有多闹心——尤其是当字符串变长后,原来用StringBuilder、LinkedList那套逐个移除的方法就开始卡壳了对吧?让我给你梳理两个更高效的解决方案,针对你的两个痛点分别拆解:
一、在字符串中查找指定子串
如果只是简单的单次查找,其实Java原生的indexOf()方法就够好用了,它直接返回子串第一次出现的索引,找不到就返回-1。如果要找所有出现的位置,只需要循环调用并更新起始索引就行:
// 单次查找子串 String mainString = "这是一个包含多个目标子串的长字符串,目标子串会重复出现目标子串"; String targetSubStr = "目标子串"; int firstPos = mainString.indexOf(targetSubStr); if (firstPos != -1) { System.out.println("第一次找到子串的位置:" + firstPos); } else { System.out.println("未找到任何匹配的子串"); } // 查找所有子串出现的位置 int currentIndex = 0; while ((currentIndex = mainString.indexOf(targetSubStr, currentIndex)) != -1) { System.out.println("找到子串,位置:" + currentIndex); currentIndex += targetSubStr.length(); // 跳过当前匹配,避免重复匹配同一位置 }
如果你的场景是更复杂的模糊匹配(比如正则表达式),可以用Pattern和Matcher类,但如果只是精确匹配,上面的方法性能已经足够,比自己手动遍历字符高效得多。
二、判断字符池能否组成目标单词
你原来的思路是逐个从字符池中移除匹配的字符,这个方法在短字符串时没问题,但一旦字符串变长,性能会直线下降——比如StringBuilder的deleteCharAt()每次删除都要移动后面所有字符,LinkedList查找目标字符也需要遍历整个列表,整体时间复杂度是O(n*m)(n是目标单词长度,m是字符池长度)。
更高效的做法是字符计数法:分别统计目标单词和字符池中每个字符的出现次数,然后对比每个字符的计数是否满足需求。这种方法的时间复杂度是O(n+m),不管字符串多长都能快速处理:
针对纯小写字母的场景(性能最优)
public boolean canFormTargetWord(String targetWord, char[] charPool) { // 提前判断:字符池长度不够直接返回false if (charPool.length < targetWord.length()) { return false; } // 统计目标单词的字符频率 int[] targetCharCounts = new int[26]; for (char c : targetWord.toCharArray()) { targetCharCounts[c - 'a']++; } // 统计字符池的字符频率 int[] poolCharCounts = new int[26]; for (char c : charPool) { poolCharCounts[c - 'a']++; } // 逐一对比字符计数 for (int i = 0; i < 26; i++) { if (poolCharCounts[i] < targetCharCounts[i]) { return false; } } return true; }
支持任意字符(含大小写、符号)的场景
如果你的字符池包含大小写字母或特殊符号,用HashMap来统计更灵活:
import java.util.HashMap; import java.util.Map; public boolean canFormTargetWord(String targetWord, String charPool) { if (charPool.length() < targetWord.length()) { return false; } Map<Character, Integer> targetCharMap = new HashMap<>(); for (char c : targetWord.toCharArray()) { targetCharMap.put(c, targetCharMap.getOrDefault(c, 0) + 1); } Map<Character, Integer> poolCharMap = new HashMap<>(); for (char c : charPool.toCharArray()) { poolCharMap.put(c, poolCharMap.getOrDefault(c, 0) + 1); } // 检查每个目标字符的计数是否满足 for (Map.Entry<Character, Integer> entry : targetCharMap.entrySet()) { char key = entry.getKey(); int requiredCount = entry.getValue(); if (poolCharMap.getOrDefault(key, 0) < requiredCount) { return false; } } return true; }
这个方法的核心是把“逐个移除匹配”的操作转化为“计数对比”,彻底避免了频繁的元素移动和查找,长字符串场景下性能提升非常明显。
内容的提问来源于stack exchange,提问作者blah
相关产品推荐
相关产品推荐

