No. 1143 【LintCode 最长AB子串 O(N)复杂度 解法】

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)时间复杂度的解法参考文末的 参考文献,并附上自己的理解与说明。

【总结解释】

一、

  1. 如果 cnt = (cntA-cntB) 曾经出现过,说明之后增加的A和B数量是相等的
  2. 也就是把 cnt相等的情况当做分隔符,处在分隔符之间的一段段就是满足题意的

二、

  1. 有一种想法是 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   23   4    5   6   7   8   99 - 3 = 6 即答案

"""

参考文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个很有意思的问题。 我们可以使用 Manacher 算法来解决这个问题,它可以在线性时间内找到一个字符串中的所有回文子串。 具体步骤如下: 1. 首先将原字符串 S 转化为一个新的字符串 T,使得 T 的长度为奇数,这可以通过在相邻的字符之间插入一个特殊字符来实现,例如将字符串 "abc" 转化为 "^a#b#c$"; 2. 定义一个数组 P,其中 P[i] 表示以字符 T[i] 为中心的最长回文子串的半径长度; 3. 定义两个变量 C 和 R,其中 C 表示当前已知的最长回文子串的中心位置,R 表示该回文子串的右边界; 4. 遍历字符串 T,对于每个位置 i,计算 P[i] 的值: 4.1 如果 i 在当前已知的最长回文子串的右边界 R 的左侧,那么可以利用已知的信息来快速计算 P[i] 的值,具体步骤如下: 4.1.1 计算 i 的对称点 j = 2C - i; 4.1.2 如果 j 的回文半径小于 R - i,那么 P[i] = P[j]; 4.1.3 否则 P[i] 至少为 R - i,需要从 R 开始扩展,直到不能再扩展为止。 4.2 如果 i 在当前已知的最长回文子串的右边界 R 的右侧,那么必须从 i 开始暴力扩展,直到不能再扩展为止。 5. 遍历数组 P,找到最长的回文子串的半径长度 mx 和其在字符串 T 中的中心位置 idx,则最长前缀回文子串为 S[0:idx-mx/2],最长后缀回文子串为 S[idx+mx/2:n-1],其中 n 是原字符串 S 的长度。 Manacher 算法的时间复杂度为 O(n),可以满足题目要求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值