一、和接近定值的三个数
给定一个数组,任意选三个数,求这三个数之和与给定的数最接近的组合。例如给定数组S={-1,2,1,-4},定值target=1。则结果是(-1+2+1)=2。
解答:先对数组排序,之后每次选一个数,然后再固定两端,用两端向中间靠近的方式找。时间复杂度O(n^2),空间复杂度O(1)。
int threeSumClosest(vector<int> &num, int target) {
sort(num.begin(),num.end());
int m = num[0]+num[1]+num[2];
for(int i=0; i<num.size(); i++){
// 先选中元素i,再固定端点i+1和n-1,向中间移动
int low = i+1, high = num.size()-1;
while(low < high){
int cur = num[i]+num[low]+num[high];
if(abs(cur-target) < abs(m-target)) m = cur;
if(m == target) return m; // 如果当前和跟目标值相等,则已经找到最接近的值
if(cur < target) low++; // 当前当前和小于目标值,则左端点右移
else high--;
}
}
return m;
}
扩展:三个数和为某个定值(去重);四个数和为某个定值(去重,在外层再加一个for循环,时间复杂度O(n^3))
二、和为定值的两个数
给定一个数组,任意选两个数,找出两个数之和等于某个定值,返回这两个数的下标(小下标在前)。
解答:用hashmap存下当前元素ai相对于target的差(target-ai)。之后再扫描一遍数组查看是否有数在hashmap之中。时间复杂度O(n),空间复杂度O(n)。
vector<int> twoSum(vector<int> &numbers, int target) {
vector<int> ret;
// hashmap
unordered_map<int,int> m;
int n = numbers.size();
// 记录元素与target的差值,value记录下标
for(int i=0; i<n; i++) m.insert(make_pair(target-numbers[i],i));
for(int i=0; i<n; i++){
// 查找hashmap里面是否存在
if(m.find(numbers[i]) != m.end() && i != m[numbers[i]]){
ret.push_back(min(i+1,m[numbers[i]]+1));
ret.push_back(max(i+1,m[numbers[i]]+1));
break;
}
}
return ret;
}
扩展:若不要求返回下标,而是返回具体哪两个数,则可以使用先排序,然后再首尾指针的方法来做。时间复杂度O(nlogn),空间复杂度O(1)。