給定字符串 str 與子串 sub,統計 sub 在 str 中**不重疊**出現的次數。例如 "java java java" 包含 "java" 3 次。
public static int countSubstring(String str, String sub) {
int count = 0;
int idx = 0;
while ((idx = str.indexOf(sub, idx)) != -1) {
count++;
idx += sub.length(); // 移動到下一個可能位置,避免重疊
}
return count;
}
優點:邏輯清晰,支援任意子串。
缺點:創建多個子字符串對象 (若用 substring),可優化為僅移動索引。
public static int countBySplit(String str, String sub) {
if (str == null || sub == null || sub.isEmpty()) return 0;
// split 會將正則元字符轉義,若 sub 含特殊字符需 Pattern.quote
String[] parts = str.split(Pattern.quote(sub));
return parts.length - 1;
}
注意:sub 若包含正則元字符 (如 .*+?[]()) 必須用 Pattern.quote 轉義,否則會按正則匹配導致錯誤。
public static int countByMatcher(String str, String sub) {
if (str == null || sub == null || sub.isEmpty()) return 0;
Pattern pattern = Pattern.compile(Pattern.quote(sub));
Matcher matcher = pattern.matcher(str);
int count = 0;
while (matcher.find()) count++;
return count;
}
進階**:若需**重疊匹配** (如 "aaa" 中 "aa" 出現 2 次),可用 Pattern.compile("(?=" + Pattern.quote(sub) + ")") 零寬斷言。
| 方案 | 時間複雜度 | 適用場景 | 備註 |
|---|---|---|---|
| indexOf 循環 | O(N*M) | 通用、無正則依賴 | 最推薦日常使用 |
| split | O(N) | 一次性統計、子串固定 | 需注意正則轉義 |
| Matcher | O(N) | 複雜匹配、重疊、邊界 | 功能最全、物件開銷稍大 |
public class SubstringCounter {
public static void main(String[] args) {
String text = "sdSS**&HGJhadHCASch& ^^";
String target = "java"; // 示例中原文統計 "java",實際文本不含,結果為 0
System.out.println("indexOf: " + countSubstring(text, target));
System.out.println("split: " + countBySplit(text, target));
System.out.println("Matcher: " + countByMatcher(text, target));
}
// 三個靜態方法放這裡...
}
面試加分點:主動說明
split的正則陷阱與Matcher的零寬斷言重疊匹配技巧,展現對 API 細節的深度理解。