题目链接:https://leetcode-cn.com/problems/3sum-with-multiplicity/
给定一个整数数组 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 种情况。
提示:
3 <= A.length <= 3000
0 <= A[i] <= 100
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
}
}