题目
2981/2982. 找出出现至少三次的最长特殊子字符串 I/II
问题描述
给你一个仅由小写英文字母组成的字符串 s 。
如果一个字符串仅由单一字符组成,那么它被称为 特殊 字符串。例如,字符串 “abc” 不是特殊字符串,而字符串 “ddd”、“zz” 和 “f” 是特殊字符串。
返回在 s 中出现 至少三次 的 最长特殊子字符串 的长度,如果不存在出现至少三次的特殊子字符串,则返回 -1 。
子字符串 是字符串中的一个连续 非空 字符序列。
示例 1:
输入:s = “aaaa”
输出:2
解释:出现三次的最长特殊子字符串是 “aa” :子字符串 “aaaa”、“aaaa” 和 “aaaa”。
可以证明最大长度是 2 。
示例 2:
输入:s = “abcdef”
输出:-1
解释:不存在出现至少三次的特殊子字符串。因此返回 -1 。
示例 3:
输入:s = “abcaba”
输出:1
解释:出现三次的最长特殊子字符串是 “a” :子字符串 “abcaba”、“abcaba” 和 “abcaba”。
可以证明最大长度是 1 。
提示:
3 <= s.length <= 50
s 仅由小写英文字母组成。
方法一
解题思路
暴力求解:遍历所有子串,找到出现三次的最长特殊子串
算法过程
- 定义一个字典,存储特殊子串出现的次数
- 从最大长度的子串开始查找,由于子串至少要有三个,最长子串长度l为len(s)-2
- 已知子串长度,将子串左端从0开始遍历,当左端为0,右端为l,直到右端为字符串末尾截止。判断子串是否为特殊子串,是则统计到字典中,特殊子串个数大于等于3返回长度。
- 不满足3返回-1
代码编写
class Solution:
def maximumLength(self, s: str) -> int:
word_count = defaultdict(lambda: 0)
for l in range(len(s)-2,0,-1):
right = l
left = 0
while right <= len(s):
s1 = s[left:right]
if s1.count(s1[0]) == len(s1):
word_count[s1] += 1
if word_count[s1] == 3:
return l
left+=1
right+=1
return -1
复杂度分析
时间复杂度:O(n^2)
空间复杂度:O(n^2)
方法二
解题思路
遍历一遍字符串,统计每一段连续的特殊子串中字母出现的次数
如aabcccaaabbaa
a:[2,3,2]
b:[1,2]
c:[3]
排序每一个字母中的列表,从大到小
a:[3,2,2]
出现三次的最长子串肯定在列表前三个当中
1.长度a[0]-2子串有3个
2.长度a[0]-1有两个,加上a[1]一个,至少有三个
3.长度a[2]有一个,加上a[0]、a[1],至少有三个
ans=max(a[0]-2,min(a[0]-1,a[1]),a[2])
算法过程
无
代码编写
class Solution:
def maximumLength(self, s: str) -> int:
word_count = defaultdict(list)
cnt = 0
for i,c in enumerate(s):
cnt+=1
if i+1 == len(s) or s[i+1] != c:
word_count[c].append(cnt)
cnt = 0
ans = 0
for c in word_count.values():
c.sort(reverse=True)
c.extend([0,0])
ans = max(ans,c[0]-2,min(c[0]-1,c[1]),c[2])
return ans if ans else -1
复杂度分析
时间复杂度:O(nlog(n))
空间复杂度:O(n)
方法三
解题思路
遍历一遍字符串,统计每一段连续的特殊子串中字母出现的次数
如aabcccaaabbaa
a:[2,3,2]
b:[1,2]
c:[3]
对每一个列表进行二分查找其长度
取s的中位数为初始长度,检测满足该长度下的连续字符串个数,满足则存储长度并增加长度,不满足则缩小长度。
算法过程
无
代码编写
class Solution:
def maximumLength(self, s: str) -> int:
words = defaultdict(list)
cnt = 0
for i,c in enumerate(s):
cnt+=1
if i+1==len(s) or c!=s[i+1]:
words[c].append(cnt)
cnt = 0
res = -1
for vec in words.values():
left, right = 1, len(s) - 2 # 字符串s
while left <= right:
mid = (left + right) // 2
count = 0
for x in vec: # 单个字符连续个数列表
if x >= mid: # 判断是否比当前字符串的一半长
count += x - mid + 1 # 获取mid长度下,连续字符串的个数
if count >= 3: # 该长度下个数大于等于3,长度符合条件
res = max(res, mid)
left = mid + 1 # 增加长度
else:
right = mid - 1 # 减少长度
return res
复杂度分析
时间复杂度:O(nlog(n))
空间复杂度:O(n)