题目描述
Given an array of integers, 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. Please note that your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution.
Input: numbers={2, 7, 11, 15}, target=9
Output: index1=1, index2=2
题目大意:
给一个数组,找出其中是否有两个数之和等于给定的值。类似的还有3 sum ,4 sum ..等 K sum
问题。其实原理是差不多的,这样想:先取出一个数,那么我只要在剩下的数字里面找到两个数字使得他们的和等于(target – 那个取出的数)。
分析:
1、暴力法,复杂度是 O(n^2),会 TLE。
2、先排序,然后从开头和结尾同时向中间查找,原理也比较简单。复杂度O(nlogn)
3、使用HashMap。把每个数都存入map中,任何再逐个遍历,查找是否有 target – nubmers[i]。 时间复杂度 O(n)
方法1:暴力法
typedef struct Node{
int id,val;
}Node;
bool compare(const Node & a,const Node & b){
return a.val < b.val;
}
class Solution {
public:
vector<int> twoSum(vector<int> &numbers, int target) {
Node nodes[numbers.size()];
for(unsigned int i=0; i<numbers.size(); i++){
nodes[i].id = i+1;
nodes[i].val = numbers[i];
}
sort(nodes, nodes+numbers.size(), compare);
int start=0,end=numbers.size()-1;
vector<int> ans;
while(start < end){
if(nodes[start].val + nodes[end].val == target){
if(nodes[start].id > nodes[end].id)
swap(nodes[start].id , nodes[end].id);
ans.push_back(nodes[start].id);
ans.push_back(nodes[end].id);
return ans;
}else if( nodes[start].val + nodes[end].val < target ){
start++;
}else
end--;
}
}
};
方法2:先排序
ublic class Solution {
static class Pair implements Comparable<Pair> {
int value, index;
public Pair(int v, int id) {
value = v;
index = id;
}
@Override
public int compareTo(Pair b) {
return this.value - b.value;
}
}
public static int[] twoSum(int[] numbers, int target) {
int[] res = new int[2];
Pair[] pairs = new Pair[numbers.length];
// get pairs and sort
for (int i = 0; i < numbers.length; ++i) {
pairs[i] = new Pair(numbers[i], i + 1);
}
Arrays.sort(pairs);
// two points
int left = 0, right = numbers.length - 1, sum = 0;
while (left < right) {
sum = pairs[left].value + pairs[right].value;
if (sum == target) {
res[0] = pairs[left].index;
res[1] = pairs[right].index;
if (res[0] > res[1]) {
// swap them
res[0] ^= res[1];
res[1] ^= res[0];
res[0] ^= res[1];
}
break;
} else if (sum > target) {
--right;
} else {
++left;
}
}
return res;
}
}
方法3:HashMap
public class Solution {
public static int[] twoSum(int[] numbers, int target) {
int[] res = new int[2];
HashMap<Integer, Integer> nums = new HashMap<Integer, Integer>();
for (int i = 0; i < numbers.length; ++i) {
// add i-th number
Integer a = nums.get(numbers[i]);
if (a == null)
nums.put(numbers[i], i);
// find (target - numbers[i])
a = nums.get(target - numbers[i]);
if (a != null && a < i) {
res[0] = a + 1;
res[1] = i + 1;
break;
}
}
return res;
}
}
思路是循环一次,每次都判断当前数组索引位置的值在不在hashtable里,不在的话,加入进去,key为数值,value为它的索引值;在的话,取得他的key,记为n(此时n一定小于循环变量i),接下来再在hashtable中查找(target-当前数值)这个数,利用了hashtable中查找元素时间为常数的优势,如果找到了就结束,此处需要注意的是,如果数组中有重复的值出现,那么第二次出现时就不会加入到hashtable里了,比如3,4,3,6;target=6时,当循环到第二个3时,也可以得到正确结果。