leetcode:167. Two Sum II - Input array is sorted

本文探讨了在已排序数组中寻找两数之和等于特定目标值的问题,详细介绍了哈希表、二分查找和双指针三种算法的实现方式,对比了它们的时间和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

题目描述

实现

1.哈希表

2.二分查找法

3.双指针法


题目描述

Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.

The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.

Note:

  • Your returned answers (both index1 and index2) are not zero-based.
  • You may assume that each input would have exactly one solution and you may not use the same element twice.

Example:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.

实现

1.哈希表

       与第1题相同,也可以用哈希表存储numbers的值和索引,但是这样没有利用到numbers是个有序表的性质。时间复杂度是O(n),空间复杂度是O(n)。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int i = 0;i < numbers.length;i++) {
            int x = target-numbers[i];
            if(map.containsKey(x))
                return new int[]{map.get(x)+1,i+1};
            else {
                map.put(numbers[i],i);
            }
        }
        throw new IllegalArgumentException("no res");
    }
}

2.二分查找法

        二分查找用于在一个有序表A中查找值key,返回其对应的索引。设定两个指针i,j分别指向表头、表尾,计算得到M = (i+j)/2,判断M指向的元素与要查找的key大小,如果A[M] < key,则i=M+1,否则j=M,当i<j时循环,最后当i==j且A[i]==key时得到索引i返回,否则查找失败,表中不存在key,返回-1。在twosum中二分查找用于找target-numbers[i]在numbers中的位置,如果有则返回numbers当前索引和二分查找返回值。此算法时间复杂度为O(nlogn),空间复杂度为O(1),相比哈希法在空间开销上有所降低。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        for(int i = 0;i < numbers.length;i++) {
            int x = target-numbers[i];
            int loc = bsearch(numbers, x, i+1);
            if( loc != -1) {
                return new int[] {i+1,loc+1};
            }
        }
        throw new IllegalArgumentException("no answer");
    }
    
    private int bsearch(int[] numbers, int key, int start) {
        int L = start;
        int R = numbers.length -1;
        while(L < R) {
            int M = (L+R)/2;
            if( numbers[M]<key ) {
                L = M+1;
            }
            else {
                R = M;
            }
        }
        return ((L == R && numbers[R] == key) ? R : -1);
        
    }
}

3.双指针法

       思路:target由数组中的两个数相加得到,两数相加只有三种可能,大于、小于、等于target。由于numbers是有序表,可以很方便调整相加的两数大小,于是可以设定两个指针,一个i指向数组numbers的头元素,另一个j指向尾元素,计算两数之和sum,如果sum > target,则说明需要一个更小的数与numbers[i]相加,如果sum < target,则说明需要一个更大的数与numbers[j]相加,在i<j时循环,直到sum == target。这个算法的时间复杂度是O(n),空间复杂度是O(1),比二分查找法在时间上更优。

class Solution {
    public int[] twoSum(int[] numbers, int target) {
        int start = 0;
        int end = numbers.length -1;
        while( start < end ) {
            if( numbers[start] + numbers[end] < target )
                start++;
            else if( numbers[start] + numbers[end] > target )
                end--;
            else
                return new int[] { start+1, end+1 };
        }
        throw new IllegalArgumentException("no answer");
    }
    
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值