目录
题目描述
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");
}
}