算法题:找出一个数组中和为n的两个数

题目

  • 有一个递增的数组 [1,2,4,7,11,15] 和 n = 15
  • 数组中有两个数,和是n。即 4 + 11 === 15
  • 写一个js函数,找出这两个数

常规思路

  • 循环嵌套
  • 时间复杂度是O(n^2),不可用

利用递增(有序)特性

  • 随便找两个数
  • 如果和大于n,则需要向前寻找
  • 如果和小于n,则需要向后寻找 —— 二分法思想(不是真正的二分)
  • 时间复杂度降低到O(n)
/**
 * @description 找出一个数组中和为n的两个数
 * @author lsr
 */

/**
 * 找出一个数组中和为n的两个数 - 嵌套循环
 * @param arr arr
 * @param n 和
 * @returns 返回这两个数
 */
export function findTwoNumbers1(arr: number[], n: number): number[] {
  const res: number[] = []
  const length = arr.length
  if (length === 0) return res

  let flag = false
  // O(n^2)
  for (let i = 0; i < length - 1; i++) {
    for (let j = 1; j < length; j++) {
      const sum = arr[i] + arr[j]
      if (sum === n) {
        res.push(arr[i])
        res.push(arr[j])
        flag = true
        break
      }
    }
    if (flag) break
  }

  return res
}

/**
 * 找出一个数组中和为n的两个数 - 双指针
 * @param arr arr
 * @param n 和
 * @returns 返回这两个数
 */
export function findTwoNumbers2(arr: number[], n: number): number[] {
  const res: number[] = []
  const length = arr.length
  if (length === 0) return res

  let i = 0 // 头
  let j = length - 1 // 尾
  while (i < j) {
    const sum = arr[i] + arr[j]
    if (sum > n) {
      // 当前和大于目标和,j 需向前移动
      j--
    } else if (sum < n) {
      // 当前和小于目标和,i 需向后移动
      i++
    } else {
      res.push(arr[i])
      res.push(arr[j])
      break
    }
  }

  return res
}

// 功能测试
const arr = [
  1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2,
  1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 4, 7, 11, 15
]
const n = 15
// const res1 = findTwoNumbers1(arr, n)
// const res2 = findTwoNumbers2(arr, n)
// console.log(res1)
// console.log(res2)

// 性能测试
console.time('findTwoNumbers1')
for (let i = 0; i < 100 * 10000; i++) {
  findTwoNumbers1(arr, n)
}
console.timeEnd('findTwoNumbers1') // 1045.7412109375 ms

console.time('findTwoNumbers2')
for (let i = 0; i < 100 * 10000; i++) {
  findTwoNumbers2(arr, n)
}
console.timeEnd('findTwoNumbers2') // 69.4990234375 ms

单元测试

/**
 * @description 找出一个数组中和为n的两个数 test
 * @author lsr
 */

import {
  findTwoNumbers1,
  findTwoNumbers2
} from '@/01-algorithm/two-numbers-sum'

describe('找出一个数组中和为n的两个数', () => {
  it('空数组', () => {
    const res = findTwoNumbers2([], 15)
    expect(res).toEqual([])
  })

  it('正常情况', () => {
    const arr = [1, 2, 4, 7, 11, 15]
    const n = 15
    const res = findTwoNumbers2(arr, n)
    expect(res).toEqual([4, 11])
  })

  it('找不到的情况', () => {
    const arr = [1, 2, 4, 7, 11, 15]
    const n = 20
    const res = findTwoNumbers2(arr, n)
    expect(res).toEqual([])
  })
})

划重点

  • 时间复杂度达到O(n^2),是不可用算法
  • 凡有序,必二分!!!
  • 优化嵌套循环,可以考虑双指针
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,这是一个关于算法的问。这个问可以用哈希表来解决,具体步骤是: 1. 创建一个哈希表,用来存放数组中的元素和它们的索引。 2. 遍历组,对于每个元素,查找哈希表中是否存在另外一个元素,使得个元素的和等于目标值。若存在则返回个元素的索引,若不存在则将该元素添加到哈希表中。 以下是代码实现: class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int, int> mp; for (int i = 0; i < nums.size(); ++i) { int complement = target - nums[i]; if (mp.count(complement)) return {mp[complement], i}; mp[nums[i]] = i; } return {}; } }; ### 回答2: 要找出数组中和为目标值的个数,可以使用双指针法来解决。 首先,我们需要定义个指针,一个指向组的开头,一个指向组的末尾。 然后,我们进入一个循环,循环的条件是个指针不相遇。 在循环内部,我们比较个指针所指向的元素的和与目标值的大小关系。如果和小于目标值,说明我们需要增加和的值,所以将左指针向右移动一位。如果和大于目标值,说明我们需要减小和的值,所以将右指针向左移动一位。如果和等于目标值,说明我们找到了符合条件的个数,直接返回这个数即可。 最后,如果循环结束还没有找到符合条件的个数,说明不存在这样的个数,可以返回空组或者指定一个特殊值来表示没有找到。 这种解法的时间复杂度为O(n),其中n是组的长度。由于只需要使用常量的额外空间,所以空间复杂度为O(1)。 ### 回答3: 要找出数组中和为目标值的个数,可以使用双指针的方法来解决。首先对组进行排序,然后定义个指针,一个指向组的起始位置,一个指向组的末尾位置。根据排序后的组特点,如果当前个指针指向的的和大于目标值,则将末尾指针向前移动一位;如果和小于目标值,则将起始指针向后移动一位;如果和等于目标值,则找到了符合条件的个数。不断移动指针,直到找到符合条件的个数或者指针交叉为止。 以下是实现该算法的示例代码: ```python def findTwoNumbers(nums, target): # 对组进行排序 nums.sort() # 定义起始位置和末尾位置的指针 left = 0 right = len(nums) - 1 while left < right: # 计算当前个指针所指向的的和 curr_sum = nums[left] + nums[right] if curr_sum == target: return [nums[left], nums[right]] elif curr_sum < target: # 如果和小于目标值,则将起始指针向后移动 left += 1 else: # 如果和大于目标值,则将末尾指针向前移动 right -= 1 # 如果没有找到符合条件的个数,则返回空列表 return [] ``` 使用该函可以找到数组中和为目标值的个数,时间复杂度为 O(nlogn),其中 n 为组的长度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值