給定整數數組 numbers 和目標值 target,找出兩個數的索引(1-based),使其和等於 target。假設恰好存在一組解,且 index1 < index2。
示例:numbers={2,7,11,15}, target=9 → index1=1, index2=2
雙層循環枚舉所有數對,時間復雜度 O(n²),大數據下超時。
核心思想:遍歷數組時,將 數值 → 索引 存入哈希表。對於當前元素 x,查找 target - x 是否已存在。
關鍵陷阱:當 x == target - x(即 x = target/2)時,不能使用同一元素兩次。需檢查哈希表中存儲的索引是否與當前索引不同。
class Solution {
public:
vector<int> twoSum(vector<int> &numbers, int target) {
unordered_map<int, int> hash_map; // 數值 -> 索引 (0-based)
vector<int> result;
// 第一遍:構建哈希表
for (int i = 0; i < numbers.size(); ++i) {
hash_map[numbers[i]] = i;
}
// 第二遍:查找互補數
for (int i = 0; i < numbers.size(); ++i) {
int complement = target - numbers[i];
auto it = hash_map.find(complement);
if (it != hash_map.end()) {
int j = it->second;
if (i != j) { // 關鍵:排除同一元素
result.push_back(min(i, j) + 1); // 轉 1-based
result.push_back(max(i, j) + 1);
return result; // 題目保證唯一解,直接返回
}
}
}
return result; // 理論上不會執行到這裡
}
};
邊構建哈希表邊查找,避免同元素問題(因為當前元素尚未加入表):
vector<int> twoSum(vector<int> &nums, int target) {
unordered_map<int, int> mp;
for (int i = 0; i < nums.size(); ++i) {
int complement = target - nums[i];
if (mp.count(complement)) {
return {mp[complement] + 1, i + 1};
}
mp[nums[i]] = i;
}
return {};
}
| 方法 | 時間 | 空間 | 備註 |
|---|---|---|---|
| 暴力雙循環 | O(n²) | O(1) | 簡單但慢 |
| 雙遍歷哈希表 | O(n) | O(n) | 需處理同元素去重 |
| 單遍歷哈希表 | O(n) | O(n) | 推薦,自然避免同元素 |
O(n) 降為 O(1),總體 O(n)+1,注意 index1 < index2 順序