第91题 给一个数组,找出其中和为n的两个元素(两数之和)
- 有一个递增数组
[1,2,4,7,11,15]和一个n=15 - 数组中有两个数,和是
n。即4 + 11 = 15 - 写一个函数,找出这两个数
思路分析
- 嵌套循环,找到一个数,然后去遍历下一个数,求和判断,时间复杂度是
O(n^2)基本不可用 - 双指针方式,时间复杂度降低到
O(n)- 定义
i指向头 - 定义
j指向尾 - 求
arr[i] + arr[j]的和,如果大于n,则j向前移动j--,如果小于n,则i向后移动i++
- 定义
- 优化
嵌套循环,可以考虑双指针
寻找和为 n 的两个数(嵌套循环)
/**
* 寻找和为 n 的两个数(嵌套循环)
* @param arr arr:number[]
* @param n n:number
*/
function findTowNumbers1(arr, n) {
const res = []
const length = arr.length
if (length === 0) return res
// 时间复杂度 O(n^2)
for (let i = 0; i < length - 1; i++) {
const n1 = arr[i]
let flag = false // 是否得到了结果(两个数加起来等于n)
// j从i + 1开始,获取第二个数n2
for (let j = i + 1; j < length; j++) {
const n2 = arr[j]
if (n1 + n2 === n) {
res.push(n1)
res.push(n2)
flag = true
break // 调出循环
}
}
// 调出循环
if (flag) break
}
return res
}
查找和为 n 的两个数(双指针)
随便找两个数,如果和大于
n的话,则需要向前寻找,如果小于n的话,则需要向后寻找 --二分的思想
/**
* 查找和为 n 的两个数(双指针)
* @param arr arr:number[]
* @param n n:number
*/
function findTowNumbers2(arr, n) {
const res = []
const length = arr.length
if (length === 0) return res
// 
let i = 0 // 定义i指向头
let j = length - 1 // 定义j指向尾
// 求arr[i] + arr[j]的和,如果大于n,则j向前移动j--,如果小于n,则i向后移动i++
// 时间复杂度 O(n)
while (i < j) {
const n1 = arr[i]
const n2 = arr[j]
const sum = n1 + n2
if (sum > n) { //sum 大于 n ,则 j 要向前移动
j--
} else if (sum < n) { // sum 小于 n ,则 i 要向后移动
i++
} else {
// 相等
res.push(n1)
res.push(n2)
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, 4, 7, 11, 15]
console.info(findTowNumbers2(arr, 15))
// 性能测试
// 寻找和为 n 的两个数(嵌套循环)
console.time('findTowNumbers1')
for (let i = 0; i < 100 * 10000; i++) {
findTowNumbers1(arr, 15)
}
console.timeEnd('findTowNumbers1') // 730ms
// 查找和为 n 的两个数(双指针)
console.time('findTowNumbers2')
for (let i = 0; i < 100 * 10000; i++) {
findTowNumbers2(arr, 15)
}
console.timeEnd('findTowNumbers2') // 102ms
// 结论:双指针性能优于嵌套循环方式
