跳至主要內容

和为S的两个数字

微信公众号:储凡2023/2/11大约 4 分钟

和为S的两个数字

题目链接

题目描述

输入一个升序数组 array 和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,返回任意一组即可,如果无法找出这样的数字,返回一个空数组即可。

刷题思路

一些基本数学知识:

  • 根据x+y=sumxy最小 由于array是递增的,则xy 距离越远 xy值越小,x y距离越近xy值越大
  • x+y=(x+m)+(y-m)=sum 假设x是左边元素,y是右边元素 即:y>x
  • 可以理解乘积(x+m)(y-m)=xy-(y-x)*m-m^2 其中y-x>0 m^2
  • 所以m值越大,其实(x+m)(y-m)越小,也就是x与y间隔也大 xy越小 ,由于array是递增的,所以只需要找到第一个满足和为sum的即可

基于这样的特性,有以下方案

方案一:

  • 利用双指针left 、 right
  • 逐步向左、向右逼近

方案二:

  • 利用二分查找

方案三:

  • 利用Map存储已有元素

方案四:

  • 直接暴力解法

代码实现

/**
 * 【中等】和为S的两个数字
 */

/**
 * 利用双指针
 */
function findNumbersWithSumOne(array, sum) {
  let left = 0
  let right = array.length - 1
  while (left < right) {
    if (array[left] + array[right] === sum) {
      // 第一个就返回
      return [array[left], array[right]]
    }
    else if (array[left] + array[right] > sum) {
      // 向左逼近
      right--
    }
    else {
      // 向右逼近
      left++
    }
  }
  return []
}

/**
 * 注意数组array是递增的
 * 利用二分查找
 */
function findNumbersWithSumTwo(array, sum) {
  let left = 0
  let right = array.length - 1
  // 将最小值标记设置成最大
  let min = array[right] * array[right]
  let result = []
  while (left < right) {
    if (array[left] + array[right] === sum) {
      // 符合条件
      if (min > array[left] * array[right]) {
        // 最小值
        min = array[left] * array[right]
        result = [array[left], array[right]]
      }
      left++
      right--
    }
    else if (array[left] + array[right] < sum) {
      // 左边向右逼近
      left++
    }
    else {
      // 右边向左逼近
      right--
    }
  }
  return result
}

/**
 * 利用map来存放数据,便于查找
 */
function findNumbersWithSumThree(array, sum) {
  const resultMap = new Map()
  for (const a of array) {
    resultMap.set(a, true)
  }
  for (const a of array) {
    if (resultMap.has(sum - a)) {
      return [a, sum - a]
    }
  }
  return []
}

/**
 * 暴力方案
 */
function findNumbersWithSumFour(array, sum) {
  const len = array.length
  for (let index = 0; index < len; index++) {
    const firstValue = array[index]
    for (let j = index + 1; j < len; j++) {
      if (array[j] === sum - firstValue) {
        return [firstValue, array[j]]
      }
    }
  }
  return []
}

const testArr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]

console.log(findNumbersWithSumOne(testArr, 21))
console.log(findNumbersWithSumTwo(testArr, 21))
console.log(findNumbersWithSumThree(testArr, 21))
console.log(findNumbersWithSumFour(testArr, 21))

一些建议

  • 了解二分(折半)查找的原理
  • 熟练掌握Map数据结构的一些api方案
  • 有时候暴力方案比较直接,存在较大优化空间

双指针模型:

function FindNumbersWithSum(array, sum) {
  let left = 0
  let right = array.length - 1
  while (left < right) {
    if (array[left] + array[right] > sum) {
      right--
    }
    else if (array[left] + array[right] < sum) {
      left++
    }
    else {
      return [array[left], array[right]]
    }
  }
  return []
}

更新日志

2024/7/29 15:43
查看所有更新日志
  • 5a2b2-feat: 移除markdown-cli模块,采用prettier校验文档格式
  • a3cca-refactor: 替换eslint规则,使用antfu/eslint模块 (#138)
  • c0f2d-refactor: 升级vuepress相关版本,优化项目结构 (#137)
  • 6b33b-feat(ES6): 新增2016新增特性和ts文档
  • 06596-feat: 算法相关文档新增固定链接,优化导入代码配置
  • 9b9e4-feat: 算法相关文档更新,删除讨论链接 (#88)
  • b0275-feat(markdownlint-cli): 添加markdown文档校验,支持lint脚本自动格式化文档
  • 5f1e1-feat: 导航栏、侧边栏内容修改,新增目录对应的文档
  • 02ab1-style: 文档目录调整,修改mdEnhance配置
  • fc602-feat: 新增算法文档
  • 74e84-docs(algorithm): 新增一些文档
  • ced18-docs: 更新一些文档,优化导航栏
  • a23ce-refactor: 新增manuscript目录,优化文稿结构
  • e34c0-style(code): 代码风格eslint格式化,新增部分文档
  • 74aa9-docs(algorithm): 新增一些文档
  • 3c22c-refactor: 新增Eslint配置,修改相关代码风格
  • 9bbe9-feat: 修改导航栏结构,添加文档
  • e4c74-feat: 新增算法源码
贡献者: chu fan,Chu Fan,chufan,142vip.cn,chufan443