题目

给定四个包含整数的数组列表 A , B , C , D,计算有多少个元组 (i, j, k, l),使得 A[i] + B[j] + C[k] + D[l] = 0

为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500。所有整数的范围在 四数相加II - 图1四数相加II - 图2 之间,最终结果不会超过 四数相加II - 图3

例如:

  1. 输入:
  2. A = [ 1, 2]
  3. B = [-2,-1]
  4. C = [-1, 2]
  5. D = [ 0, 2]
  6. 输出:
  7. 2
  8. 解释:
  9. 两个元组如下:
  10. 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
  11. 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0

方案一(穷举法)

func fourSumCount(A []int, B []int, C []int, D []int) int {
    N := len(A)
    count := 0
    for i := 0; i < N; i++ {
        for j := 0; j < N; j++ {
            for a := 0; a < N; a++ {
                for b := 0; b < N; b++ {
                    if A[i] + B[j] + C[a] + D[b] == 0 {
                        count += 1
                    }
                }
            }
        }
    }

    return count
}
  • 时间复杂度 四数相加II - 图4
  • leetcode 超时

方案二

func fourSumCount(A []int, B []int, C []int, D []int) int {
    // 只需 (A[a] + B[b] + C[c]) in m4 即可
    m4 := map[int]int{}
    for _, d := range D {
        m4[-d] += 1
    }
    // 利用m4 和 C[] 构建 m3
    // 只需 (A[a] + B[b]) in m3 即可
    m3 := map[int]int{}
    for _, c := range C {
        for k, v := range m4 {
            m3[k - c] += v
        }
    }
    // 同理构建 m2
    m2 := map[int]int{}
    for _, b := range B {
        for k, v := range m3 {
            m2[k - b] += v
        }
    }
    // 构建 m1
    m1 := map[int]int{}
    for _, a := range A {
        for k, v := range m2 {
            m1[k - a] += v
        }
    }

    return m1[0]
}
  • 时间复杂度 四数相加II - 图5
  • leetcode 仍旧超时

代码可以优化的地方有很多,主要思想是

  1. A[a] + B[b] == val, 可能有多种 a, b 的组合,但是后续计算时候只需要计算val即可,不需要每一个组合都算出来
  2. 倒着计算使得更容易缓存结果

方案三(A + B = -(C + D))

func fourSumCount(A []int, B []int, C []int, D []int) int {
    // A + B = -(C + D)
    m1 := map[int]int{}
    for _, a := range A {
        for _, b := range B {
            m1[a + b] += 1
        }
    }

    count := 0
    for _, c := range C {
        for _, d := range D {
            if v, ok := m1[-(c + d)]; ok {
                count += v
            }
        }
    }

    return count
}
  • 时间复杂度 四数相加II - 图6

原文

https://leetcode-cn.com/explore/learn/card/hash-table/207/conclusion/828/