python - 总和等于 0 的最大子数组

标签 python algorithm arrays

这是一个典型的面试问题。给定一个既包含正元素又包含负元素且不为 0 的数组,找到其和等于 0 的最大子数组。我试图解决这个问题。这就是我想出的。

def sub_array_sum(array,k=0):
    start_index = -1
    hash_sum = {}
    current_sum = 0
    keys = set()
    best_index_hash = {}
    for i in array:
        start_index += 1
        current_sum += i
        if current_sum in hash_sum:
            hash_sum[current_sum].append(start_index)
            keys.add(current_sum)
        else:
            if current_sum == 0:
                best_index_hash[start_index] = [(0,start_index)]
            else:
                hash_sum[current_sum] = [start_index]
    if keys:
        for k_1 in keys:
            best_start = hash_sum.get(k_1)[0]
            best_end_list = hash_sum.get(k_1)[1:]
            for best_end in best_end_list:
                if abs(best_start-best_end) in best_index_hash:
                    best_index_hash[abs(best_start-best_end)].append((best_start+1,best_end))
                else:
                    best_index_hash[abs(best_start-best_end)] = [(best_start+1,best_end)]

    if best_index_hash:
        (bs,be) = best_index_hash[max(best_index_hash.keys(),key=int)].pop()
        return array[bs:be+1]
    else:
        print "No sub array with sum equal to 0"


def Main():
    a = [6,-2,8,5,4,-9,8,-2,1,2]
    b = [-8,8]
    c = [-7,8,-1]
    d = [2200,300,-6,6,5,-9]
    e = [-9,9,-6,-3]
    print sub_array_sum(a)
    print sub_array_sum(b)
    print sub_array_sum(c)
    print sub_array_sum(d)
    print sub_array_sum(e)

if __name__ == '__main__':
    Main()

我不确定这是否会满足所有边缘情况。如果有人可以对此发表评论,那就太好了我还想将其扩展为等于任何 K 而不仅仅是 0 的总和。我应该怎么做。任何进一步优化它的建议也很有帮助。

最佳答案

你已经给出了一个很好的线性时间解决方案(比此时其他两个答案更好,它们是二次时间的),基于每当 sum(i .. j) = 0 时,它必须是sum(0 .. i-1) = sum(0 .. j) 反之亦然。本质上,您计算所有 i 的前缀和 sum(0 .. i),构建一个哈希表 hash_sum,其中 hash_sum[x] 是 i 拥有的所有位置的列表总和(0 .. i)= x。然后你遍历这个哈希表,一次一个总和,寻找由多个前缀组成的任何总和。在所有此类多次生成的总和中,您选择由一对相距最远的前缀生成的总和 - 这是最长的。

由于您已经注意到使该算法成为线性时间所需的关键洞察力,我对您为什么在第二个循环的 best_index_hash 中建立这么多不必要的东西感到有点困惑。对于给定的总和 x,构成该总和的相距最远的一对前缀将始终是 hash_sum[x] 中的最小和最大条目,它们必然是第一个和最后一个条目(因为那是它们被附加的顺序),所以不需要循环遍历它们之间的元素。事实上,您甚至根本不需要第二个循环:您可以在第一个循环中保持运行最大值,方法是将 start_index 视为最右边的端点。

要处理任意差异 k:我们需要找到前缀总和为 current_sum 的最左边出现,而不是找到最左边出现的前缀总和 current_sum - k。但这只是 first_with_sum{current_sum - k}

以下代码未经测试,但应该可以工作:

def sub_array_sum(array,k=0):
    start_index = -1
    first_with_sum = {}
    first_with_sum{0} = -1
    best_start = -1
    best_len = 0
    current_sum = 0
    for i in array:
        start_index += 1
        current_sum += i
        if current_sum - k in first_with_sum:
            if start_index - first_with_sum{current_sum - k} > best_len:
                best_start = first_with_sum{current_sum - k} + 1
                best_len = start_index - first_with_sum{current_sum - k}
        else:
            first_with_sum{current_sum} = start_index

    if best_len > 0:
        return array[best_start:best_start+best_len-1]
    else:
        print "No subarray found"

在开头设置 first_with_sum{0} = -1 意味着我们不必将从索引 0 开始的范围视为特例。请注意,此算法不会改进原始算法的渐近时间或空间复杂度,但它更易于实现,并且在包含零和子数组的任何输入上使用的空间都较少。

关于python - 总和等于 0 的最大子数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27265233/

相关文章:

python - 读取 .VTK 多数据文件并将其转换为 Numpy 数组

php - 按二级数组计数对数组排序

python - 使用python查找适合文件中像素的物理坐标

python - 简化python中Excel单元格名称的排序

javascript - 将 URL 参数传递给 Python

algorithm - k = k + 1 是什么意思?对于用解决方案对实际问题进行分类有什么建议吗?

c# - 如何对多个不同大小的矩形进行分类

python - 在终端窗口中运行 Selenium (chromedriver)?

c++ - 在无法存储值的情况下计算系列?

c - 使用 Strtok 存储字符串片段