- leetcode: Two Sum | LeetCode OJ
- lintcode: (56) 2 Sum
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
, 如果是找數組中一個值為target
該多好啊!遍歷一次就知道了,我只想說,too naive... 難道要將數組中所有元素的兩兩組合都求出來與target
比較嗎?時間複雜度顯然為 target
所對應的判斷條件——
基本思路有了,現在就來看看怎麼實現,顯然我們需要額外的空間(也就是哈希表)來保存已經處理過的 target
減去當前索引後的值在哈希表中找到了,那麼就將哈希表中相應的索引返回,大功告成!
class Solution {
public:
/*
* @param numbers : An array of Integer
* @param target : target = numbers[index1] + numbers[index2]
* @return : [index1+1, index2+1] (index1 < index2)
*/
vector<int> twoSum(vector<int> &nums, int target) {
vector<int> result;
const int length = nums.size();
if (0 == length) {
return result;
}
// first value, second index
unordered_map<int, int> hash(length);
for (int i = 0; i != length; ++i) {
if (hash.find(target - nums[i]) != hash.end()) {
result.push_back(hash[target - nums[i]]);
result.push_back(i + 1);
return result;
} else {
hash[nums[i]] = i + 1;
}
}
return result;
}
};
- 異常處理。
- 使用 C++ 11 中的哈希表實現
unordered_map
映射值和索引。 - 找到滿足條件的解就返回,找不到就加入哈希表中。注意題中要求返回索引值的含義。
哈希表用了和數組等長的空間,空間複雜度為
class Solution:
"""
@param numbers : An array of Integer
@param target : target = numbers[index1] + numbers[index2]
@return : [index1 + 1, index2 + 1] (index1 < index2)
"""
def twoSum(self, numbers, target):
hashdict = {}
for i, item in enumerate(numbers):
if (target - item) in hashdict:
return (hashdict[target - item] + 1, i + 1)
hashdict[item] = i
return (-1, -1)
Python 中的dict
就是天然的哈希表,使用 enumerate 可以同時返回索引和值,甚為方便。按題意似乎是要返回 list, 但個人感覺返回 tuple 更為合理。最後如果未找到符合題意的索引,返回(-1, -1)
.
但凡可以用空間換時間的做法,往往也可以使用時間換空間。另外一個容易想到的思路就是先對數組排序,然後使用兩根指針分別指向首尾元素,逐步向中間靠攏,直至找到滿足條件的索引為止。
class Solution {
public:
/*
* @param numbers : An array of Integer
* @param target : target = numbers[index1] + numbers[index2]
* @return : [index1+1, index2+1] (index1 < index2)
*/
vector<int> twoSum(vector<int> &nums, int target) {
vector<int> result;
const int length = nums.size();
if (0 == length) {
return result;
}
// first num, second is index
vector<pair<int, int> > num_index(length);
// map num value and index
for (int i = 0; i != length; ++i) {
num_index[i].first = nums[i];
num_index[i].second = i + 1;
}
sort(num_index.begin(), num_index.end());
int start = 0, end = length - 1;
while (start < end) {
if (num_index[start].first + num_index[end].first > target) {
--end;
} else if(num_index[start].first + num_index[end].first == target) {
int min_index = min(num_index[start].second, num_index[end].second);
int max_index = max(num_index[start].second, num_index[end].second);
result.push_back(min_index);
result.push_back(max_index);
return result;
} else {
++start;
}
}
return result;
}
};
- 異常處理。
- 使用
length
保存數組的長度,避免反複調用nums.size()
造成性能損失。 - 使用
pair
組合排序前的值和索引,避免排序後找不到原有索引信息。 - 使用標準庫函數排序。
- 兩根指針指頭尾,逐步靠攏。
遍歷一次原數組得到pair
類型的新數組,時間複雜度為
Note lintcode 上的題要求時間複雜度在
$$O(n \log n)$$ 時,空間複雜度為$$O(1)$$ , 但問題是排序後索引會亂掉,如果要保存之前的索引,空間複雜度一定是$$O(n)$$ ,所以個人認為不存在較為簡潔的$$O(1)$$ 實現。如果一定要$$O(n)$$ 的空間複雜度,那麼只能用暴搜了,此時的時間複雜度為$$O(n^2)$$ .