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
刚看到题目想到的解法是类似于冒泡排序的思想,使用两重循环寻找顺序容器中每一个数字是否可以与其余数字加和等于target,代码如下:
class Solution {
public:
vector
twoSum(vector
&numbers, int target) {
vector
result;
for (int i = 0; i < numbers.size() - 1; i++) {
for (int j = i + 1; j < numbers.size(); j++) {
if (numbers[i] + numbers[j] == target) {
result.push_back(i + 1);
result.push_back(j + 1);
return result;
}
}
}
}
};
提交上去发现提示Time Limit Exceeded 错误,说明系统无法接受时间复杂度为O(n^2)的算法,因此考虑新的算法,通过再次观察题目可以发现,时间消耗较大的地方是当遍历容器中的数字numbers[i]时在剩余数字中查找target-numbers[i]的时候,时间复杂度为O(n),因此考虑更快速的查找算法。
可以想到的快速的查找算法有HashMap,时间复杂度为O(1)以及排序之后的二分查找,时间复杂度为O(logn)。
首先实现HashMap查找算法,但是遇到一个问题,在C++中没有现成的HashMap库函数可以使用,便使用map代替,通过查找资料[1]发现map的一些特别之处,以map<int, int> m为例:
- 在查找map时,如果使用下标方式查找,如m[key],如果此时m中不存在key,此操作会自动在m中插入一个键值为key,值为类型初始值的一个pair,这样便改变了map的结构,因此不能使用,需要考虑使用count()和find()函数,这两个函数都不会造成多余的插入操作。
- map中的键值必须保证是唯一的,因此在插入同一个键值多次时,后插入的会覆盖前插入的,然而题目中的容器中会出现重复值,因此将map中的值类型改成vector<int>,这样可以保存相同值的多个位置。
- map中的find()函数是通过红黑树索引查找的,效率不比HashMap,具体细节未探明。
class Solution {
public:
static void myInsert(vector
&result, int pst1, int pst2) {
if (pst1 < pst2) {
result.push_back(pst1);
result.push_back(pst2);
}
else {
result.push_back(pst2);
result.push_back(pst1);
}
return;
}
vector
twoSum(vector
&numbers, int target) {
vector
result;
map
> numbersMap; for (int i = 0; i < numbers.size(); i++) { vector
pst = numbersMap[numbers[i]]; pst.push_back(i + 1); numbersMap[numbers[i]] = pst; } for (map
>::const_iterator map_it = numbersMap.begin(); map_it != numbersMap.end(); map_it++) { map
>::const_iterator it = numbersMap.find(target - map_it->first); if (it != numbersMap.end()) { if (map_it->first == target - map_it->first) { if (it->second.size() == 2) return it->second; else continue; } else myInsert(result, map_it->second[0], it->second[0]); } else continue; } return result; } };
除此之外,还发现了一个C++和C在定义结构体时的区别,以后要注意,C中在定义结构体时一般是
struct Node {
int value;
Node* point;
};
class Solution {
public:
struct Node {
int value;
int position;
};
static bool cmp(Node num1, Node num2) {
return num1.value < num2.value;
}
static void myPushBack(vector
&result, Node num1, Node num2) {
if (num1.position < num2.position) {
result.push_back(num1.position);
result.push_back(num2.position);
}
else {
result.push_back(num2.position);
result.push_back(num1.position);
}
return;
}
vector
twoSum(vector
&numbers, int target) {
vector
result;
vector
newNumbers; for (int i = 0; i < numbers.size(); i++) { Node node; node.value = numbers[i]; node.position = i + 1; newNumbers.push_back(node); } sort(newNumbers.begin(), newNumbers.end(), cmp); int begin = 0; int end = newNumbers.size() - 1; while (begin < end) { if (newNumbers[begin].value + newNumbers[end].value == target) { myPushBack(result, newNumbers[begin], newNumbers[end]); return result; } else if (newNumbers[begin].value + newNumbers[end].value < target) { begin ++; } else { end --; } } } };