两数之和 II - 输入有序数组 - 双指针 O(N) 时间复杂度

来源 https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted/

思路

仅仅是遍历数组,找到数组中和为target的两个数;这个是利用了二数之和的解法,属于暴力破解了, 针对于无序数组;没有利用到本题的有序数组的特性;

my ugly code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func twoSum(numbers []int, target int) []int {
    var res []int
	length := len(numbers)

	for i := 0; i < length-1; i++ {
		for j := i + 1; j < length; j++ {
			sum := numbers[i] + numbers[j]
			if sum == target {
				res = append(res, i+1)
				res = append(res, j+1)
			}
		}
	}

	return res
}

明显上述代码效率就不高, 甚至会达到O(n^2)的复杂度;

对于有序的数组, 我会想到二分查找;

​ 在数组中找到两个数,使得它们的和等于目标值,可以首先固定第一个数,然后寻找第二个数,第二个数等于目标值减去第一个数的差。利用数组的有序性质,可以通过二分查找的方法寻找第二个数。为了避免重复寻找,在寻找第二个数时,只在第一个数的右侧寻找。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
func twoSum(numbers []int, target int) []int {
    for i := 0; i < len(numbers); i++ {
        low, high := i + 1, len(numbers) - 1
        for low <= high {
            mid := (high - low) / 2 + low
            if numbers[mid] == target - numbers[i] {
                return []int{i + 1, mid + 1}
            } else if numbers[mid] > target - numbers[i] {
                high = mid - 1
            } else {
                low = mid + 1
            }
        }
    }
    return []int{-1, -1}
}

复杂度分析

​ 时间复杂度:O(nlogn),其中 n 是数组的长度。需要遍历数组一次确定第一个数,时间复杂度是 O(n),寻找第二个数使用二分查找,时间复杂度是 O(logn),因此总时间复杂度是 O(nlogn)。

​ 空间复杂度:O(1)。

高手思路赏析

解题思路:

使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。

  • 如果两个指针指向元素的和 sum == target,那么得到要求的结果;

  • 如果 sum > target,移动较大的元素,使 sum 变小一些;

  • 如果 sum < target,移动较小的元素,使 sum 变大一些。

数组中的元素最多遍历一次,时间复杂度为 O(N)。只使用了两个额外变量,空间复杂度为 O(1)。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// from  CyC2018
public int[] twoSum(int[] numbers, int target) {
    if (numbers == null) return null;
    int i = 0, j = numbers.length - 1;
    while (i < j) {
        int sum = numbers[i] + numbers[j];
        if (sum == target) {
            return new int[]{i + 1, j + 1};
        } else if (sum < target) {
            i++;
        } else {
            j--;
        }
    }
    return null;
}