我发现了这个面试问题,我想不出一个比O(N^2 *P)更好的算法:
给定一个由P个自然数组成的向量(1,2,3,...,P)和另一个长度为N的向量(其元素来自第一个向量),在第二个向量中找到最长的子序列,使得所有元素都均匀分布(具有相同的频率)。
示例:(1,2,3)和(1,2,1,3,2,1,3,1,2,3,1).最长的子序列在区间2,10中,因为它包含来自第一个序列的相同频率的所有元素(1出现三次,2出现三次,3出现三次)。
时间复杂度应为O(N * P)。
发布于 2012-04-17 22:21:10
如果内存使用率并不重要,那么很容易...
您可以给矩阵维数N*p
,并在列(i)中保存一个值,该值与p
在第二个向量的(i)第一个元素之间查找的元素的数量相对应。
完成矩阵后,您可以搜索列i
中的所有元素都不同的列i
。最大i
就是答案。
发布于 2012-04-19 13:14:07
使用随机化,您可以将其降低到线性时间。其思想是将每个P值替换为一个随机整数,以便这些整数之和为零。现在查找两个相等的前缀和。这允许一些小的误报机会,我们可以通过检查我们的输出来补救。
在Python 2.7中:
# input:
vec1 = [1, 2, 3]
P = len(vec1)
vec2 = [1, 2, 1, 3, 2, 1, 3, 1, 2, 3, 1]
N = len(vec2)
# Choose big enough integer B. For each k in vec1, choose
# a random mod-B remainder r[k], so their mod-B sum is 0.
# Any P-1 of these remainders are independent.
import random
B = N*N*N
r = dict((k, random.randint(0,B-1)) for k in vec1)
s = sum(r.values())%B
r[vec1[0]] = (r[vec1[0]]+B-s)%B
assert sum(r.values())%B == 0
# For 0<=i<=N, let vec3[i] be mod-B sum of r[vec2[j]], for j<i.
vec3 = [0] * (N+1)
for i in range(1,N+1):
vec3[i] = (vec3[i-1] + r[vec2[i-1]]) % B
# Find pair (i,j) so vec3[i]==vec3[j], and j-i is as large as possible.
# This is either a solution (subsequence vec2[i:j] is uniform) or a false
# positive. The expected number of false positives is < N*N/(2*B) < 1/N.
(i, j)=(0, 0)
first = {}
for k in range(N+1):
v = vec3[k]
if v in first:
if k-first[v] > j-i:
(i, j) = (first[v], k)
else:
first[v] = k
# output:
print "Found subsequence from", i, "(inclusive) to", j, "(exclusive):"
print vec2[i:j]
print "This is either uniform, or rarely, it is a false positive."
发布于 2012-04-17 22:18:33
这里有一个观察:你不能得到一个均匀分布的序列,它在长度上不是P
的乘积。这意味着您只需检查N
的子序列,即P
、2P
、3P
...long - (N/P)^2
这类序列。
https://stackoverflow.com/questions/10192443
复制相似问题