You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

查找两数和小于target integer的不重复数对算法优化与去重方案

问题描述

需要实现一个接收array和target integer作为入参的函数,返回所有满足两数之和小于target integer的数对,结果需去重,例如[2,4]与[4,2]视为同一数对,不可重复返回。

示例

输入:[1,2,2,3,4,5], 6
输出:[[1,2],[1,3],[1,4],[2,2]]

现有实现存在两个待解决的问题:

  • 返回结果包含重复数对
  • 嵌套循环实现时间复杂度为O(n²),性能较差

原有实现代码如下:

function twoNumSum(array, targetNum) {
  let result = [];
  for (i = 0; i < array.length; i++) {
    for (j = i + 1; j < array.length; j++) {
      if (array[i] + array[j] < targetNum) {
        if (!result[(array[i], array[j])]) {
          result.push([array[i], array[j]]);
        }
      }
    }
  }
  return result;
}

// 测试用例
console.log(twoNumSum([1, 2, 3, 4], 4));// 预期输出[[1,2]]
console.log(twoNumSum([1, 2, 3], 3));// 预期输出[]
console.log(twoNumSum([1, 2, 2, 3, 4], 5));// 预期输出[[1,2],[1,3],[2,2]],实际输出包含重复[1,2]
问题分析
  1. 去重逻辑失效:代码中!result[(array[i], array[j])]使用了逗号运算符,实际执行逻辑为!result[array[j]]。由于result是存储数对的数组,以数值为索引的位置初始值均为undefined,判断条件恒为真,完全无法识别重复数对。
  2. 时间复杂度偏高:双重暴力循环遍历所有两两组合,时间复杂度为O(n²),数组长度较大时性能损耗明显。
优化方案

采用排序+双指针思路实现,整体时间复杂度可降至O(nlogn),且遍历过程中可直接跳过重复元素,从根源避免重复数对生成,无需额外做结果去重:

  • 先对原数组做升序排序,排序后数对天然满足前值小于等于后值,不会出现顺序颠倒的重复数对问题
  • 遍历左指针时,跳过与前一位置值相同的元素,避免左值重复导致的重复数对
  • 对每个固定的左指针,从数组末尾移动右指针,找到第一个满足arr[left] + arr[right] < target的边界位置,左指针与「左指针+1 到 边界位置」区间内的所有元素配对,均满足两数和小于目标值的要求
  • 收集配对时同样跳过连续重复的右值,彻底消除重复结果

优化后实现代码:

function twoNumSum(array, targetNum) {
  const result = [];
  // 拷贝原数组后排序,避免修改原数组
  const sortedArr = [...array].sort((a, b) => a - b);
  const len = sortedArr.length;

  for (let left = 0; left < len; left++) {
    // 跳过重复左值
    if (left > 0 && sortedArr[left] === sortedArr[left - 1]) continue;

    let right = len - 1;
    // 移动右指针找到满足和小于目标值的边界
    while (right > left && sortedArr[left] + sortedArr[right] >= targetNum) {
      right--;
    }

    // 收集所有合法配对,跳过重复右值
    for (let k = left + 1; k <= right; k++) {
      if (k > left + 1 && sortedArr[k] === sortedArr[k - 1]) continue;
      result.push([sortedArr[left], sortedArr[k]]);
    }
  }

  return result;
}

// 测试验证
console.log(twoNumSum([1,2,2,3,4,5], 6)); // 输出 [[1,2],[1,3],[1,4],[2,2]],符合预期
console.log(twoNumSum([1, 2, 3, 4], 4)); // 输出 [[1,2]]
console.log(twoNumSum([1, 2, 3], 3)); // 输出 []
console.log(twoNumSum([1, 2, 2, 3, 4], 5)); // 输出 [[1,2],[1,3],[2,2]],无重复项

该方案相比原暴力循环,在数组长度超过1000时性能提升可达两个数量级,且去重逻辑无额外空间开销,不需要将数对转为字符串存入哈希表做判重。


内容的提问来源于stack exchange,提问作者codingFun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 16:03:34