1. 程式人生 > >題解:三數之和的多種可能(923)

題解:三數之和的多種可能(923)

給定一個整數陣列 A,以及一個整數 target 作為目標值,返回滿足 i < j < k 且 A[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[i]<=100,用了雜湊之後分析了一下條件

把所有可能都列一下
題目要求x<y<z 但是對應值 i<=j<=k

3 * i != target
	i + j + k = target    //三數之和等於target
		i = j != k 
			B(i) >= 2    // i=j 有兩個以上的j
				((B(i) * (B(i)-1)) / 2) * B(k)
			B(i) < 2    // i=j 但是隻有一個i
				0
		i != j == k
			B(j) >= 2    // j=k 有兩個以上的j
				((B(j) * (B(j)-1)) / 2) * B(i)
			B(j) < 2    // j=k 但是隻有一個j
				0
		i != j != k    //三個數不同
			B(i) * B(j) * B(k)
	i + j + k != target    // 不等於target
		0
3 * i == target //三個相同數的和等於target
	B(i) >= 3  //有三個以上相同的數
		B(i) * (B(i)-1) * (B(i) -2) / (3 * 2 * 1)
	B(i) < 3   //相同數小於三個
		0

列條件的時候覺得條件很多,如果一條條列出來的話會很麻煩,但是列出來之後發現有許多可以合併的條件,比如i==j!=k的兩種情況就可以合併,因為當B(i)<2時,B(i)=1,B(i)-1=0,表示式的值為0,所以將可以合併的判斷合併之後就會只剩下四個,但是再一分析發現,i=j!=k和i!=j=k其實是一個條件,只不過i,j,k的取值不同,但是隻用一個判斷條件的話後面也能判斷到另一個條件,所以最終合併之後會只有三個條件。分別是i=j=k,i=j!=k,i!=j!=k,然後寫出程式碼

object Solution {
    def threeSumMulti(A: Array[Int], target: Int): Int = {
        var result:Double = 0    //防止數字過大超範圍
        val B = new Array[Int](105)    //防止越界
        for(i <- 0 until(A.length)) B(A(i)) += 1 //雜湊
        for(i <- 0 until B.length){
          for(j <- 0 until B.length){
            if(B(i)!=0&&B(j)!=0){    //存在i和j
              val k = target - i - j    
              if(k>=0&&k<=100 && B(k)>0){    //k存在
                if(i == j && j == k)    //i==j==k
                  result += (B(i).toDouble * (B(i) - 1) * (B(i) - 2)) / 6
                else if(i == j && j != k)    //i==j!=k
                  result += (B(i) * (B(i) - 1)) / 2 * B(k)
                else if(i < j && j < k)    //i!=j!=k
                  result += B(i) * B(j) * B(k)
              }
            }
          }
        }
        (result % 1000000007).toInt
    }
}