Leetcode 第 1 題(Two Sum)
Leetcode 第 1 題
昨天去逛了逛這個網站,感覺挺有意思。準備有空的時候就做一兩道。
第一道題目是這樣的:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].UPDATE (2016/2/13):
The return format had been changed to zero-based indices. Please read the above updated description carefully.
這個題目相對來說很簡單。最直接的做法是遍歷這個陣列中的任意兩個元素。計算他們的和是否滿足要求。下面貼一個最原始,最粗暴的解法:
class Solution {
public:
vector<int> twoSum(vector<int> &nums, int target)
{
vector <int> result;
int N = nums.size();
for (int i = 0; i < N - 1; i++)
{
for (int j = i+1; j < N; j++)
{
if (numbers[i] + numbers[j] == target)
{
result.push_back(i+1);
result.push_back(j+1 );
return result;
}
}
}
return result;
}
};
兩重迴圈,演算法的時間複雜度為
nums[i] + nums[j] == target
每次判斷時都要重新計算一下兩個元素的和。實際上這步求和計算可以剩下來。下面是改進後的程式碼:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ret;
int N = nums.size();
for(int i = 0; i < N-1; i++)
{
int val = target - nums[i];
for(int j = i+1; j < N; j++)
{
if(nums[j] == val)
{
ret.push_back(i);
ret.push_back(j);
return ret;
}
}
}
}
};
這樣改進之後,運算速度大約可以提高 30%。
不過還是挺慢的。理論上來說,遍歷一遍這個陣列就能獲得全部資訊了。沒有必要反覆的遍歷這麼多次。
舉個例子:
Given nums = [2, 7, 11, 15], target = 9
含顯然,[2, 7, 11, 15] 與它配對的陣列是 [7, 2, -2, -6]。 這個陣列是可以提前算出來的。之後我們只要在這個數組裡查詢有沒有我們需要的數字就好了。選擇好合適的資料結構,這個查詢的工作的時間複雜度可以做到
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int, int> lookup;
int N = nums.size();
for(int i = 0; i < N; i++)
{
lookup.insert(pair<int, int>(nums[i], i));
}
for(int i = 0; i < N; i++)
{
int value = target - nums[i];
if(lookup.count(value) && lookup[value] != i)
{
vector<int> ret;
ret.push_back(i);
ret.push_back(lookup[value]);
return ret;
}
}
}
};
改成這個程式碼之後執行速度提高了一個數量級。但是也只是打敗了27.73% 的程式碼提交者。所以還是有改進的餘地。
想一想,這個程式碼可以改進的地方也就是這兩個迴圈了。現在第一個迴圈用來建立map。第二個迴圈使用這個 map。 其實用一個迴圈就可以。因為答案由兩個陣列成,當我們的map 資料不全時,可能會錯過一次配對,但是肯定不會錯過第二次配對的。按照這個思路,程式碼進一步修改為:
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
map<int, int> lookup;
int N = nums.size();
for(int i = 0; i < N; i++)
{
int value = nums[i];
if( lookup.count(target - value) )
{
vector<int> ret;
ret.push_back(lookup[target - value]);
ret.push_back(i);
return ret;
}
lookup.insert(pair<int, int>(value, i));
}
}
};
現在這個程式碼已經可以打敗 45% 的答題者了。剩下的可以優化的地方已經不多了,折騰了一會兒,一直沒能突破這個 45%。。。
各位大神們,求一個更好的程式碼。