给定一系列头部和尾部,我想计算数量显着的子串,其中头部的数量不小于尾部的数量。我想在O(NlogN)时间内实现这一目标。
示例输入:
[ 'H', 'T', 'H', 'T', 'T', 'H' ]
示例输出:
11
解释
{H} {H} {H}
{H, T} {T, H} {H, T} {T, H}
{H, T, H}
{H, T, H, T}
{H, T, T, H}
{H, T, H, T, T, H}
我相信我当前的算法是O(N ^ 2)。我递归地解决了这个问题,用两端切成的硬币列表进行迭代。
这是我目前的算法。如何实现O(NLogN)时间?
def count_sequences( data ):
print go(range(0,len(data)),data)
seen = set()
def go(rang,data):
if tuple(rang) in seen: return 0
seen.add(tuple(rang))
h = 0
summ = 0
if len(rang)==0: return 0
for i in rang:
if data[i] == 'H': h += 1
summ += go(rang[1:],data)
summ += go(rang[:-1],data)
if len(rang) == 1:
if h ==1: return 1
else: return 0
if h > (len(rang)-1)/2 :
return 1 + summ
else: return summ
答案 0 :(得分:2)
这是一个O(n)解决方案。
想象一下,而不是H和T,你的数组中有1和-1。这减少了计算非负和子阵列数量的问题。这是一个已知问题,可以解决计算累积数组和查找反转次数的问题。
这可以在O(n ^ 2)搜索对i <0中天真地计算。 j其中A [i]> A [j]。它可以使用合并排序变体优化为O(n log n)。
但在这种情况下,特别是,数组中的值最多为n,连续值的精确度为1的绝对差值,因此我们可以创建一个算法,在O(n)中动态计算这些反转:< / p>
def solve(A):
count = 0
accum = 0
total = 0
seen = {0: 1}
for i, element in enumerate(A):
if element == 'H':
count += 1
accum -= seen.get(count, 0)
else:
accum += seen.get(count, 0)
count -= 1
seen[count] = seen.get(count, 0) + 1
total += (i + 1 - accum)
return total
print solve([ 'H', 'T', 'H', 'T', 'T', 'H' ])
print solve([ 'T', 'H', 'H', 'H', 'T' ])
此算法主要基于one I've read here。