问题:
给你一个字符串 s ,请你返回满足以下条件且出现次数最大的 任意 子串的出现次数:
子串中不同字母的数目必须小于等于 maxLetters 。
子串的长度必须大于等于 minSize 且小于等于 maxSize 。
示例 :
输入:s = “aababcaab”, maxLetters = 2, minSize = 3, maxSize = 4
输出:2
解释:子串 “aab” 在原字符串中出现了 2 次。
它满足所有的要求:2 个不同的字母,长度为 3 (在 minSize 和 maxSize 范围内)。
直接解法:
复杂度是, O ( m * n * n)
最外层的循环是 m = maxSize - minSize
里面的两层循环,是 n 平方
class Solution_maxFreq{
func maxFreq(_ s: String, _ maxLetters: Int, _ minSize: Int, _ maxSize: Int) -> Int {
let cnt = s.count
guard cnt >= minSize, minSize <= maxSize else {
return 0
}
var len = minSize
var result = 0
while len <= maxSize {
var i = 0
while i <= cnt - len {
var j = i + 1
var tmpCnt = 1
let from = s[i..<i+len]
if from.maxLetters <= maxLetters{
result = max(result, 1)
while j <= cnt - len {
let to = s[j..<j+len]
// print("from: ", from)
// print("to: ", to)
if from == to{
tmpCnt += 1
result = max(result, tmpCnt)
}
j += 1
}
}
i += 1
}
len += 1
}
return result
}
}
优化
记录字符串,字串的个数,要用哈希表
这样就把上面内部的两层循环,拿掉了一层,
复杂度,变成了 O ( m * n)
利用本题目的条件,
找出个数,不用打印,所有满足条件的字符串
这里有一个贪心算法处理
-
maxSize 的子串可以,
-
minSize 的子串一定也可以,他包含的字符更少
这样就把最外层的循环,也拿掉了,
复杂度,变成了 O ( n )
优化后的代码:
class Solution_try_three {
func maxFreq(_ s: String, _ maxLetters: Int, _ minSize: Int, _ maxSize: Int) -> Int {
let cnt = s.count
guard cnt >= minSize, minSize <= maxSize else {
return 0
}
var result = 0
var occurenceDict = [Substring: Int]()
var i = 0
while i <= cnt - minSize {
let start = s.index(s.startIndex, offsetBy: i)
let end = s.index(s.startIndex, offsetBy: i+minSize)
let tmp = s[start..<end]
if tmp.maxLetters <= maxLetters{
if let val = occurenceDict[tmp]{
occurenceDict[tmp] = val + 1
result = max(val + 1, result)
}
else{
occurenceDict[tmp] = 1
result = max(1, result)
}
}
i += 1
}
return result
}
}
辅助方法
extension Substring {
var maxLetters: Int{
return Set(self).count
}
}
新的问题:
对于复杂的案例字符串,性能消耗太大
直接点就是, leet code 编译不过
因为对字符串,频繁的截取子串
针对 Swfit 的优化:
class Solution {
func maxFreq(_ s: String, _ maxLetters: Int, _ minSize: Int, _ maxSize: Int) -> Int {
var substrsCounter = [String:Int]()
// 伸缩
var subStr = ""
var charsCounter = [Character:Int]()
for ch in s {
subStr.append(ch)
charsCounter.updateValue(1 + (charsCounter[ch] ?? 0), forKey: ch)
if subStr.count == minSize {
if charsCounter.count <= maxLetters {
substrsCounter.updateValue(1 + (substrsCounter[subStr] ?? 0), forKey: subStr)
}
let ch = subStr.removeFirst()
if let c = charsCounter[ch] {
if c == 1 {
charsCounter.removeValue(forKey: ch)
} else {
charsCounter.updateValue(c - 1, forKey: ch)
}
}
}
}
return substrsCounter.values.max() ?? 0
}
}
注意到,上面没有每一次循环,使用下标,获得子字符串,
通过一个字符串的伸缩,一次保存,循环内可用