跳至主要內容

leetcode 167. 两数之和 II - 输入有序数组

张威大约 2 分钟数据结构与算法哈希二分查找双指针

167. 两数之和 II - 输入有序数组open in new window

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列 ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1]numbers[index2] ,则 1 <= index1 < index2 <= numbers.length

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1index2

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

方法一:哈希

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        unordered_map<int, int> hashMap;
        for(int i = 0; i < numbers.size(); ++i) {
            if(hashMap.count(target - numbers[i])) {
                return {hashMap[target - numbers[i]] + 1,i + 1};
            }
            hashMap[numbers[i]] = i;
        }
        return {};
    }
};
  • 一般用于
  • 时间复杂度O(n) 空间复杂度O(n)

方法二:二分查找

  • 对有序数组 可以使用二分查找法 查找target - nums.at(i)
  • 时间复杂度O(nlogn) 空间复杂度O(1)
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
         for(int i = 0; i < numbers.size(); ++i) {
            int ret = binarySearch(numbers, i + 1, numbers.size() - 1 , target - numbers[i]);
            if(ret > -1) {
                return {i + 1, ret + 1};
            }
        }
        return {-1, -1};
    }

    int binarySearch(vector<int>& nums,int left, int right, int target) {   //左闭右闭
        if(left < 0 || right > nums.size() || left > right) {
            return -1;
        }
        while(left <= right) {
            int middle = left + (right - left) / 2;
            if(target > nums[middle]) {
                left = middle + 1;
            }
            else if(target == nums[middle]) {//判断相等时一定要小心,不要写成赋值
                return middle;
            }
            else {
                right = middle - 1;
            }
        }
        return -1;
    }
};

方法三 :双指针法

  • 时间复杂度:O(n),其中 n 是数组的长度。两个指针移动的总次数最多为 n 次。
  • 空间复杂度:O(1)。
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int left = 0;
        int right = numbers.size() - 1;
        if(numbers[left] > target && numbers[left] > 0) {
            return {-1, -1};
        }

        while(left < right) {
            while(left < right && numbers[left] + numbers[right] > target) {
                --right;
            }
            while(left < right && numbers[left] + numbers[right] < target) {
                ++left;
            }
            if(numbers[left] + numbers[right] == target) {
                return {left + 1, right + 1};
            }
        }
        return {-1, -1};
    }
};