100道前端面试题(十三): 找出一个数组中和为 n 的两个数(TS+单元测试)

80 阅读1分钟

前言

1-1.webp

题目如下:输入一个有序数组(从小到大),一个变量n(number),找出数组中两个元素之和为n的元素,使用数组形式返回


样例输出

示例1:

输入:

arr = [1, 2, 4, 7, 11, 15]

n = 15

输出:

arr = [4, 11]

示例2:

输入:

arr = [1, 2, 4, 7, 11, 15]

n = 100

输出:

arr = []

方法一(嵌套循环)

解题思路

通过for循环先遍历第一个元素,之后内部嵌套for循环,从该元素的下一位开始遍历,直到两个元素之和为n,或者都不为n,那么进行下一次循环,由于双for嵌套, 没有跳步情况因此时间复杂度为O(n^2)

代码实现

export function findTowNumbers1(arr: number[], n: number): number[] {
    const res: number[] = []

    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 // 是否得到了结果

        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
}

方法二(双指针)

解题思路

只使用一次for循环,别从头部和末尾开始移动,当两个元素之和大于n,末尾元素向前移动一位;当两个当两个元素之和小于n,头部元素向后移动一位,继续比较,由于只使用了一次for循环,因此时间复杂度为O(n)

代码实现

export function findTowNumbers2(arr: number[], n: number): number[] {
    const res: number[] = []

    const length = arr.length
    if (length === 0) return res

    let i = 0 // 头
    let j = length - 1 // 尾

    // 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
}

性能测试

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

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

性能测试结果验证了我们对两个方法的时间复杂度的推测

单元测试

describe('两数之和', () => {
    it('正常情况', () => {
        const arr = [1, 2, 4, 7, 11, 15]
        const res = findTowNumbers2_1(arr, 15)
        expect(res).toEqual([4, 11])
    })

    it('空数组', () => {
        const res = findTowNumbers2_1([], 100)
        expect(res).toEqual([])
    })

    it('找不到结果', () => {
        const arr = [1, 2, 4, 7, 11, 15]
        const n = 100
        const res = findTowNumbers2_1(arr, n)
        expect(res).toEqual([])
    })
})