No. 1143 【LintCode 最长AB子串 O(N)复杂度 解法】
题目描述
给你一个只由字母’A’和’B’组成的字符串s,找一个最长的子串,要求这个子串里面’A’和’B’的数目相等,输出该子串的长度。
这个子串可以为空。
s的长度n满足 2<=n<=1000000。
样例1
输入: s = “ABAAABBBA”
输出: 8
【解释】:
子串 s[0,7] 和子串 s[1,8] 满足条件,长度为 8。
样例2
输入: s = “AAAAAA”
输出: 0
【解释】:
s 中除了空字串,不存在 ‘A’ 和 ‘B’ 数目相等的子串。
1. 暴力算法
暴力解法的时间复杂度太高,必然超时。
def maxLenFun(s):
L = len(s)
if L <= 1:
return 0
max_len = 0
for i in range(0, L):
for j in range(i + 1, L):
sub = s[i:j+1]
num_a = sub.count('A')
num_b = sub.count('B')
if num_a == num_b:
max_len = max(max_len, j - i+1)
return max_len
if __name__ == '__main__':
s = 'ABBABBABA' # 6
ans = maxLenFun(s)
print(ans)
2. 解法二(分割区间法)
O(N)时间复杂度的解法参考文末的 参考文献,并附上自己的理解与说明。
【总结解释】
一、
- 如果 cnt = (cntA-cntB) 曾经出现过,说明之后增加的A和B数量是相等的
- 也就是把 cnt相等的情况当做分隔符,处在分隔符之间的一段段就是满足题意的
二、
- 有一种想法是 cnt == 0 的之前都是满足题意的,但是并非如此。比如"ABB ABBABA" 这个字符串,是逆序来的,所以还要逆序来一遍,总而言之距离两个端点最远的cnt==0才是答案
class Solution:
"""
@param s: a String consists of A and B
@return: the longest of the longest string that meets the condition
"""
def getAns(self, s):
n = len(s)
first = {
} # 新建哈希表
first[0] = 0
cntA = 0
cntB = 0
ans = 0
for i in range(n):
if s[i] == 'A':
cntA += 1
else:
cntB += 1
cnt = cntA - cntB # cntA - cntB 即A的数量减去B的数量
if cnt in first: # 因为每个循环都要查询,所以用哈希表可以缩减查询时间 在表中就查询
ans = max(ans, i + 1 - first[cnt])
else:
first[cnt] = i + 1 # 不在表中就添加
print(first)
print(cntA, cntB)
return ans
if __name__ == '__main__':
s = 'ABBABBABA'
solution = Solution()
print(solution.getAns(s))
【具体说明如下】
"""
S 'A B B A B B A B A'
i 0 1 2 3 4 5 6 7 8
cntA 1 1 1 1 2 2 3 3 4
cntB 0 1 2 2 3 4 4 5 5
cnt 1 0 -1 0 -1 2 -1 -2 -1
value 1 2 3 4 5 6 7 8 9
hashmap = {
key(cnt):value(i+1), ...}
在 cnt中,值为0和-1都出现过 ,但是由-1作为边界隔断的区间比较大
即
cnt 1 0 【-1 0 -1 2 -1 -2 -1】
value 1 2 【 3 4 5 6 7 8 9】
9 - 3 = 6 即答案
"""