题解:三数之和的多种可能(923)

题目链接: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 种情况。

 

提示:

  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
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值