[leetCode]1297. 子串的最大出现次数
枚举法
由于minSize
与maxSize
都小于26
,所以可以枚举minSize
与maxSize
之间的字符串,对于起始位置i
和结束位置j
的字符串,使用一个集合存放不同的字符。枚举每个字符时将其加入集合,如果集合的大小小于maxLetters
并且并且字符串的长度在 minSize
与 maxSize
之间,那么我们就找到了一个满足条件的字符串。
我们使用一个无序映射(HashMap)存放所有满足条件的字符串。对于无序映射中的每个键值对,键表示字符串,值表示该字符串出现的次数。在枚举完所有的字符串后,无序映射中出现次数最多的那个字符串即为答案。
class Solution {
public int maxFreq(String s, int maxLetters, int minSize, int maxSize) {
int n = s.length();
Map<String, Integer> occ = new HashMap<>();
int ans = 0;
for (int i = 0; i < n; i++) {
Set<Character> exist = new HashSet<>();
StringBuffer strbuf = new StringBuffer();
for (int j = i; j < Math.min(n, i + maxSize); j++) {
char c = s.charAt(j);
exist.add(c);
if (exist.size() > maxLetters)
break;
strbuf.append(c);
if (j - i + 1 >= minSize) {
String substr = strbuf.toString();
if (occ.get(substr) == null) {
occ.put(substr, 1);
}else {
occ.put(substr, occ.get(substr) + 1);
}
ans = Math.max(ans, occ.get(strbuf.toString()));
}
}
}
return ans;
}
}
可行性优化
假设字符串 T 在给定的字符串 S 中出现的次数为 k,那么 T 的任意一个子串出现的次数至少也为 k,即 T 的任意一个子串在 S 中出现的次数不会少于 T 本身。这样我们就可以断定,在所有满足条件且出现次数最多的的字符串中,一定有一个的长度恰好为 minSize。
class Solution {
public int maxFreq(String s, int maxLetters, int minSize, int maxSize) {
int n = s.length();
Map<String, Integer> occ = new HashMap<>();
int ans = 0;
for (int i = 0; i < n - minSize + 1; i++) {
HashSet<Character> exist = new HashSet<>();
for (int j = i; j < i + minSize; j++) {
char c = s.charAt(j);
exist.add(c);
}
if (exist.size() > maxLetters)
continue;
String cur = s.substring(i, i + minSize);
if (occ.get(cur) == null) {
occ.put(cur, 1);
} else {
occ.put(cur, occ.get(cur) + 1);
}
ans = Math.max(ans, occ.get(cur));
}
return ans;
}
}