Given an array of integers, find two numbers such that they add up to a specific target number.
The functiontwoSumshould return_indices_of the two numbers such that they add up to the target, where index1 must be less than index2. Please note that your returned answers (both index1 and index2) areNOTzero-based.
Notice
You may assume that each input would have exactly one solution
Example
numbers=[2, 7, 11, 15], target=9
return[1, 2]
Either of the following solutions are acceptable:
O(n) Space, O(nlogn) Time
O(n) Space, O(n) Time
2.Code
Version 1: Sort+Two pointers(空间上更好)--O(nlogn)--Time limit exceed
先排序,head在头,tail在尾。
sum>target --> tail--
sum<target --> head++
public int[] twoSum(int[] numbers, int target) {
if(numbers==null || numbers.length==0){
return null;
}
int[] result=new int[2];
Arrays.sort(numbers);
int head=0;
int tail=numbers.length-1;
while(head<tail){
int sum=numbers[head]+numbers[tail];
if(sum>target){
tail--;
}
else if(sum<target){
head++;
}
else{
result[0]=head;
result[1]=tail;
}
}
return result;
}
Version 2: HashMap(时间上更好) O(n)
public int[] twoSum2(int[] numbers, int target){
if(numbers==null || numbers.length==0){
return null;
}
int[] result=new int[2];
HashMap<Integer,Integer> map=new HashMap<Integer,Integer>();
for(int i=0;i<numbers.length;i++){
if(!map.containsKey(numbers[i])){
map.put(target-numbers[i], i);
}else{
//both index1 and index2) are NOT zero-based.
result[0]=i+1;
result[1]=map.get(numbers[i])+1;
}
}
Arrays.sort(result);
return result;
}
可以通过一个哈希表减少时间复杂度:
int[] twoSum(int[] nums, int target) {
int n = nums.length;
HashMap<Integer, Integer> index = new HashMap<>();
// 构造一个哈希表:元素映射到相应的索引
for (int i = 0; i < n; i++)
index.put(nums[i], i);
for (int i = 0; i < n; i++) {
int other = target - nums[i];
// 如果 other 存在且不是 nums[i] 本身
if (index.containsKey(other) && index.get(other) != i)
return new int[] {i, index.get(other)};
}
return new int[] {-1, -1};
}
while (lo < hi) {
int sum = nums[lo] + nums[hi];
// 记录索引 lo 和 hi 最初对应的值
int left = nums[lo], right = nums[hi];
if (sum < target) lo++;
else if (sum > target) hi--;
else {
res.push_back({left, right});
// 跳过所有重复的元素
while (lo < hi && nums[lo] == left) lo++;
while (lo < hi && nums[hi] == right) hi--;
}
}
这样就可以保证一个答案只被添加一次,重复的结果都会被跳过,可以得到正确的答案。不过,受这个思路的启发,其实前两个 if 分支也是可以做一点效率优化,跳过相同的元素:
vector<vector<int>> twoSumTarget(vector<int>& nums, int target) {
// nums 数组必须有序
sort(nums.begin(), nums.end());
int lo = 0, hi = nums.size() - 1;
vector<vector<int>> res;
while (lo < hi) {
int sum = nums[lo] + nums[hi];
int left = nums[lo], right = nums[hi];
if (sum < target) {
while (lo < hi && nums[lo] == left) lo++;
} else if (sum > target) {
while (lo < hi && nums[hi] == right) hi--;
} else {
res.push_back({left, right});
while (lo < hi && nums[lo] == left) lo++;
while (lo < hi && nums[hi] == right) hi--;
}
}
return res;
}