1. 程式人生 > >Leetcode 923:三數之和的多種可能(最詳細的解法!!!)

Leetcode 923:三數之和的多種可能(最詳細的解法!!!)

給定一個整數陣列 A,以及一個整數 target 作為目標值,返回滿足 i < j < kA[i] + A[j] + A[k] == target 的元組 i, j, k 的數量。

由於結果會非常大,請返回 結果除以 10^9 + 7 的餘數

示例 1:

輸入:A = [1,1,2,2,3,3,4,4,5,5], target = 8
輸出:20
解釋:
按值列舉(A[i],A[j],A[k]):
(1, 2, 5) 出現 8 次;
(1, 3, 4) 出現 8 次;
(2, 2, 4) 出現 2 次;
(2, 3, 3) 出現 2 次。

示例 2:

輸入:A = [1,1,2,2,2,2], target = 5
輸出:12
解釋:
A[i] = 1,A[j] = A[k] = 2 出現 12 次:
我們從 [1,1] 中選擇一個 1,有 2 種情況,
從 [2,2,2,2] 中選出兩個 2,有 6 種情況。

提示:

  1. 3 <= A.length <= 3000
  2. 0 <= A[i] <= 100
  3. 0 <= target <= 300

解題思路

這個問題其實非常簡單,我們對於a + b + c == target主要存在這樣的三種情況。

  • a==b==c
  • a==b!=c
  • a<b and b<c

實際上這是一個組合問題,所以我沒有考慮a,b,c的順序,大家仔細思考一下。

所以我們參照這篇文章 k 數和問題的思路。我們通過一個dict記錄A中的元素以及它們的個數。然後我們通過ij遍歷dict。如果是第一種情況,我們將dict[i]*(dict[i] - 1)*(dict[i] - 2)//6加入到result中,這實際上是 C n 3

C_{n}^{3} 。如果是第二種情況,我們將dict[i]*(dict[i] - 1)//2*dict[k]加入到result中,這實際上是 C n 2 C_{n}^{2} 。如果是第三種情況,我們將dict[i]*dict[j]*dict[k]加入到result中。

from collections import Counter
class Solution:
    def threeSumMulti(self, A, target):
        """
        :type A: List[int]
        :type target: int
        :rtype: int
        """
        c = Counter(A)
        result = 0
        for i, x in c.items():
            for j, y in c.items():
                k = target - i - j
                if k not in c:
                    continue
                if i == j == k: 
                    result += x * (x - 1) * (x - 2) // 6
                elif i == j != k: 
                    result += x * (x - 1) // 2 * c[k]
                elif i < j and j < k: 
                    result += x * y * c[k]

        return result % (10**9 + 7)

這是我認為思路最清晰的答案,對於其他的答案大家其實可以不用去看了,因為很容易將你拉入排列組合的泥潭中。

我將該問題的其他語言版本新增到了我的GitHub Leetcode

如有問題,希望大家指出!!!