青训营X豆包MarsCode 技术训练营第八课 | 豆包MarsCode AI 刷题

34 阅读3分钟

第482题 等和子数组问题

题目分析

给定一个非递减排序的数组 A,需要判断是否存在两个不同的、长度相同的子数组,它们的元素总和相等。子数组可以包含相同的元素,但只要起始和结束索引不同就被视为不同的子数组。如果存在这样满足条件的子数组,则返回 True,否则返回 False

解题思路

由于数组是非递减排序的,我们可以利用滑动窗口和哈希表来判断是否存在长度相同、总和相等的子数组:

  1. 通过一个哈希表 sum_map 来存储子数组的和及其起始索引。

  2. 遍历不同的子数组长度 L,从 1N // 2(超过 N // 2 时,已不可能找到两个满足条件的子数组)。

  3. 对每个长度 L 的子数组,使用滑动窗口来逐步计算每个子数组的和:

    • 对于第一个长度为 L 的子数组,直接计算其和并记录。
    • 从下一个子数组开始,通过滑动窗口方式更新和,避免重复计算。
  4. 在遍历过程中,每当计算一个子数组和时,检查该和是否已存在于哈希表中:

    • 若存在,说明找到了两个不同的、和相等的子数组,返回 True
    • 若不存在,将当前和及其起始索引存入哈希表,继续下一个子数组的检查。
  5. 如果所有情况均未找到满足条件的子数组,返回 False

解题代码

def solution(N: int, A: list) -> int:
 # 遍历子数组长度,最大为 N // 2
    for L in range(1, N // 2 + 1):
        sum_map = {}
        # 计算第一个长度为 L 的子数组的和
        current_sum = sum(A[:L])
        sum_map[current_sum] = 0  # 记录起始位置为0的子数组和
        
        # 滑动窗口遍历长度为 L 的子数组
        for i in range(1, N - L + 1):
            # 更新窗口的和
            current_sum = current_sum - A[i - 1] + A[i + L - 1]
            
            # 检查当前子数组和是否已经存在
            if current_sum in sum_map:
                # 已存在,返回 True
                return True
            else:
                # 不存在,记录到哈希表中
                sum_map[current_sum] = i
                
    # 没有找到满足条件的子数组,返回 False
    return False

if __name__ == '__main__':
    print(solution(N = 5, A = [2, 5, 5, 5, 9]) == True)
    print(solution(N = 4, A = [1, 2, 3, 4]) == False)
    print(solution(N = 6, A = [1, 1, 2, 3, 3, 6]) == True)

模块解释

  • 初始化模块:初始化哈希表 sum_map 以记录子数组和及其对应的起始索引。

  • 子数组长度遍历模块:从 1N // 2 遍历子数组长度,每次更新 sum_map

  • 滑动窗口模块:利用滑动窗口机制计算固定长度 L 的子数组和,从而降低重复计算的时间复杂度。

  • 和检查模块:在滑动窗口更新和之后,检查当前和是否存在于 sum_map 中。若存在则返回 True,否则记录该和并继续检查。

结论

通过滑动窗口和哈希表的结合,我们能在 O(N^2) 时间复杂度内判断是否存在两个不同的、长度相同且和相等的子数组,最终返回判断结果。