题目
- 有一个递增的数组 [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),是不可用算法
- 凡有序,必二分!!!
- 优化嵌套循环,可以考虑双指针