leetcode
leetcode 801 ~ 850
三数之和的多种可能

三数之和的多种可能

难度:

标签:

题目描述

代码结果

运行时间: 38 ms, 内存: 16.1 MB


/*
 * Problem: Given an integer array arr and an integer target, return the number of tuples (i, j, k)
 * such that i < j < k and arr[i] + arr[j] + arr[k] == target.
 * The result should be returned modulo 10^9 + 7.
 */

import java.util.*;
import java.util.stream.Collectors;

public class SolutionStream {
    public int threeSumMulti(int[] arr, int target) {
        final int MOD = 1000000007;
        Map<Integer, Long> countMap = Arrays.stream(arr)
                                             .boxed()
                                             .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
        long result = 0;
        List<Integer> keys = new ArrayList<>(countMap.keySet());
        for (int i = 0; i < keys.size(); i++) {
            for (int j = i; j < keys.size(); j++) {
                int x = keys.get(i);
                int y = keys.get(j);
                int z = target - x - y;
                if (countMap.containsKey(z)) {
                    long countX = countMap.get(x);
                    long countY = countMap.get(y);
                    long countZ = countMap.get(z);
                    if (x == y && y == z) {
                        result += countX * (countX - 1) * (countX - 2) / 6;
                    } else if (x == y && y != z) {
                        result += countX * (countX - 1) / 2 * countZ;
                    } else if (x < y && y < z) {
                        result += countX * countY * countZ;
                    }
                    result %= MOD;
                }
            }
        }
        return (int) result;
    }
}

解释

方法:

此题解采用哈希表和组合计数的方法来解决三数之和的问题。首先,使用Counter统计数组中每个数字的出现次数。然后,对哈希表的键进行排序,以便在后续的双重循环中按序处理。在双重循环中,对于每一对数字(i, j),计算第三个数字k为target-i-j。如果i,j和k满足条件i <= j <= k,则根据i,j和k的关系(是否相等)使用组合公式计算满足条件的三元组数量,并对结果进行累加。特别注意,只有当k也在哈希表中时,才会添加到答案中。最终,返回累加结果对1e9+7取模的值。

时间复杂度:

O(1)

空间复杂度:

O(1)

代码细节讲解

🦆
在题解中提到的组合公式计算,具体是如何实现的?例如,当 i, j, k 相等时,为什么使用 comb(cnt[i], 3)?
组合公式 comb(n, k) 计算的是从 n 个元素中选取 k 个元素的组合数。当 i, j, k 相等时,意味着我们需要从数 i 的出现次数(cnt[i])中选取3个。例如,如果 i 出现了5次,那么从这5次中挑选3个可以形成的组合数为 comb(5, 3)。这是因为每个组合代表一种不同的方式将这些相同的数分配到三个位置上(不考虑顺序)。使用 comb(cnt[i], 3) 是为了确保这种所有可能的选择都被计算在内。
🦆
为何在双重循环中只有当 k >= j 时才考虑,这种筛选条件是如何帮助减少不必要计算的?
在双重循环中,我们保持条件 i <= j <= k 来避免重复和非必要的计算。这种筛选确保每个三元组仅被考虑一次,防止例如 (1,2,3)、(2,1,3)、(3,1,2) 这样相同的三元组以不同顺序出现多次。此外,这也简化了逻辑,因为我们不需要在后续的代码中检查和管理这些重复的情况。如果 k < j,那么就会与已经设定的 i <= j 相矛盾,因此这样的组合可以直接跳过。
🦆
在哈希表的键排序后,对于每一对数字 (i, j),计算 k = target - i - j 时,如果 k 不在哈希表中,这种情况如何处理?是否直接跳过该组合?
如果在计算出 k = target - i - j 后发现 k 不在哈希表中,这意味着在数组中不存在这样的数来与 i 和 j 配对以形成符合条件的三元组。因此,这种情况下,我们应直接跳过该组合,并继续寻找其他可能的 i 和 j 组合。此处理是必须的,因为只有当三个数都存在时,才能形成有效的三元组。
🦆
最终结果需要对 10^9 + 7 取模,这一步骤在计算中有什么特别的意义或必要性?
对 10^9 + 7 取模是常用的技术,用于防止在进行大量计算时结果超出常规整数范围而导致溢出。10^9 + 7 是一个大的质数,也是常用的模数,因为它能确保运算结果保持在一个安全的范围内,同时这个数也足够大,使得在模运算下结果还能保持良好的随机性和均匀分布。此外,在编程竞赛和算法实现中,这种模运算还可以加快计算速度和增强代码的鲁棒性。

相关问题