给定一个有序1D数组(arr1, arr2, arr3, )
的元组,这是获得最小/最大索引((min1, max1), (min2, max2), (min3, max3), )
元组的最佳方法,以便数组跨越最大的公共范围?
我的意思是
min(arr[min1], arr2[min2], arr3[min3]) > max(arr1[min1-1], arr2[min2-1], arr3[min3-1])
和
max(arr[min1], arr2[min2], arr3[min3]) < min(arr1[min1+1], arr2[min2+1], arr3[min3+1])
上限是一样的吗?
一个例子:
鉴于arange(12)
和arange(3, 8)
,我想获得((3,8), (0,6))
,其目标是arange(12)[3:8] == arange(3,8)[0:6]
。
编辑请注意,数组可以是float或integer。
对不起,如果这令人困惑;我现在找不到更容易的话。非常感谢任何帮助!
EDIT2 /回答我只是意识到我在制定问题时非常糟糕。我最终解决了我想要的东西:
mins = [np.min(t) for t in arrays]
maxs = [np.max(t) for t in arrays]
lower_bound = np.max(mins)
upper_bound = np.min(maxs)
lower_row = [np.searchsorted(arr, lower_bound, side='left') for arr in arrays]
upper_row = [np.searchsorted(arr, upper_bound, side='right') for arr in arrays]
result = zip(lower_row, upper_row)
然而,这两个答案似乎对我提出的问题都有效,所以我不确定只选择其中一个作为“正确” - 我该怎么办?
答案 0 :(得分:1)
我确信有不同的方法可以做到这一点,我会使用merge算法来遍历两个数组,跟踪重叠区域。如果你不熟悉这个想法,请看一下merge-sort,希望在它和代码之间明确它是如何工作的。
def find_overlap(a, b):
i = 0
j = 0
len_a = len(a)
len_b = len(b)
in_overlap = False
best_count = 0
best_start = (-1, -1)
best_end = (-1, -1)
while i < len_a and j < len_b:
if a[i] == b[j]:
if in_overlap:
# Keep track of the length of the overlapping region
count += 1
else:
# This is a new overlapping region, set count to 1 record start
in_overlap = True
count = 1
start = (i, j)
# Step indicies
i += 1
j += 1
end = (i, j)
if count > best_count:
# Is this the longest overlapping region so far?
best_count = count
best_start = start
best_end = end
# If not in a an overlapping region, only step one index
elif a[i] < b[j]:
in_overlap = False
i += 1
elif b[j] < a[i]:
in_overlap = False
j += 1
else:
# This should never happen
raise
# End of loop
return best_start, best_end
请注意,此处的结尾将在python约定中返回,以便a=[0, 1, 2]
和b=[0, 1, 4]
,start=(0, 0)
和end=(2, 2)
。
答案 1 :(得分:1)
我认为您正在寻找longest common substring problem特殊情况的解决方案。虽然使用后缀树或动态编程可以解决这个问题,但是排序“字符串”的特殊情况更容易解决。
我认为这些代码会为您提供所需的值。它的单个参数是一系列排序的序列。它的返回值是包含每个内部序列的2元组的列表。元组值是序列之间最长公共子串的切片索引。请注意,如果没有公共子字符串,则元组将全部为(0,0)
,这将导致空切片(我认为这是正确的,因为空切片将彼此相等!)。
代码:
def longest_common_substring_sorted(sequences):
l = len(sequences)
current_indexes = [0]*l
current_substring_length = 0
current_substring_starts = [0]*l
longest_substring_length = 0
longest_substring_starts = current_substring_starts
while all(index < len(sequence) for index, sequence
in zip(current_indexes, sequences)):
m = min(sequence[index] for index, sequence
in zip(current_indexes, sequences))
common = True
for i in range(l):
if sequences[i][current_indexes[i]] == m:
current_indexes[i] += 1
else:
common = False
if common:
current_substring_length += 1
else:
if current_substring_length > longest_substring_length:
longest_substring_length = current_substring_length
longest_substring_starts = current_substring_starts
current_substring_length = 0
current_substring_starts = list(current_indexes)
if current_substring_length > longest_substring_length:
longest_substring_length = current_substring_length
longest_substring_starts = current_substring_starts
return [(i, i+longest_substring_length)
for i in longest_substring_starts]
测试输出:
>>> a=[1,2,3,4,5,6]
>>> b=[1,2,3,5,6,7]
>>> c=[3,4,5,6,7,8]
>>> longest_common_substring_sorted((a,b,c))
[(4, 6), (3, 5), (2, 4)]
我很抱歉没有很好地评论代码。该算法有点类似于mergesort的合并步骤。基本上,它跟踪每个序列的索引。在迭代时,它会递增所有与等于最小值的值对应的索引。如果所有列表中的当前值相等(对于最小值,从而彼此相对),则它知道它在所有列表的公共子串内。当子字符串结束时,将根据到目前为止找到的最长子字符串进行检查。