三数之和问题 | 豆包MarsCode AI刷题

34 阅读2分钟

代码思路

  1. 排序

    • 首先对数组进行排序,这样可以简化后续的查找过程。排序后,相同的元素会聚集在一起,便于使用双指针技术。
  2. 双指针技术

    • 使用双指针技术来寻找满足条件的三元组。固定第一个元素 arr[i],然后使用两个指针 left 和 right 分别指向 i+1 和数组的末尾。
    • 计算当前三个元素的和 current_sum = arr[i] + arr[left] + arr[right]
    • 如果 current_sum 等于目标值 t,则找到一个满足条件的三元组。
    • 如果 current_sum 小于目标值 t,则移动左指针 left 向右,以增加和的值。
    • 如果 current_sum 大于目标值 t,则移动右指针 right 向左,以减少和的值。
  3. 计数

    • 当找到一个满足条件的三元组时,计算其数量。如果 left 和 right 指向的元素相同,则计算所有可能的组合数。否则,分别计算 left 和 right 指向的元素的重复次数,并计算组合数。

前置知识点

  1. 排序算法

    • 代码中使用了 std::sort 函数对数组进行排序。std::sort 是 C++ 标准库中的一个排序函数,它使用的是快速排序、堆排序和插入排序的混合算法,平均时间复杂度为 O(n log n)
  2. 双指针技术

    • 双指针技术是一种常用的算法技巧,通常用于在有序数组中寻找满足某些条件的元素对或三元组。通过调整两个指针的位置,可以有效地减少不必要的遍历,从而提高算法的效率。
  3. 组合数学

    • 在计算满足条件的三元组数量时,需要用到组合数学的知识。例如,当 left 和 right 指向的元素相同时,计算所有可能的组合数时,使用组合公式 C(n, 2) = n * (n - 1) / 2
  4. 取模运算

    • 题目要求结果对 10^9 + 7 取模。取模运算可以防止整数溢出,并且在计算组合数时,可以避免中间结果过大。

关键步骤

  1. 排序:使用 std::sort 对数组进行排序。
  2. 双指针:在固定第一个元素后,使用双指针 left 和 right 来寻找满足条件的另外两个元素。
  3. 计数:当找到一个满足条件的三元组时,计算其数量。

完整代码

int solution(std::vector<int> &arr, int t) {
    const int MOD = 1000000007;
    int count = 0;
    int n = arr.size();
    std::sort(arr.begin(), arr.end());
    for (int i = 0; i < n - 2; ++i) {
        int left = i + 1;
        int right = n - 1;

        while (left < right) {
            int current_sum = arr[i] + arr[left] + arr[right];

            if (current_sum == t) {
                if (arr[left] == arr[right]) {
                    count += (right - left + 1) * (right - left) / 2;
                    break;
                } else {
                    int left_count = 1;
                    int right_count = 1;
                    while (left + 1 < right && arr[left] == arr[left + 1]) {
                        left_count++;
                        left++;
                    }
                    while (left < right - 1 && arr[right] == arr[right - 1]) {
                        right_count++;
                        right--;
                    }
                    count += left_count * right_count;
                    left++;
                    right--;
                }
            } else if (current_sum < t) {
                left++;
            } else {
                right--;
            }
        }
    }

    return count % MOD;
}