[LeetCode] Two Sum 兩數之和

Grandyang發表於2014-11-29

 

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, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

 

啦啦啦,歡迎開啟LeetCode刷題的旅程,這將是一段漫長而又艱辛的旅程,這是一條攀登珠穆朗瑪的皚皚雪山路,這是通向One Piece寶藏的偉大航路,這是成為火影的無比殘酷的修羅場,這是打破吊絲與高富帥之間界限的崩玉。但請不要害怕,在老船長Grandyang博主的帶領下,必將一路披荊斬棘,將各位帶到成功的彼岸,不過一定要牢記的是,不要下船,不要中途放棄,要堅持,要自我修煉,不斷成長!那麼,起航吧~這道Two Sum的題目作為LeetCode的開篇之題,乃是經典中的經典,正所謂‘平生不識TwoSum,刷盡LeetCode也枉然’,就像英語單詞書的第一個單詞總是Abandon一樣,很多沒有毅力堅持的人就只能記住這一個單詞,所以通常情況下單詞書就前幾頁有翻動的痕跡,後面都是嶄新如初,道理不需多講,雞湯不必多灌,明白的人自然明白。

這道題給了我們一個陣列,還有一個目標數target,讓我們找到兩個數字,使其和為target,乍一看就感覺可以用暴力搜尋,但是猜到OJ肯定不會允許用暴力搜尋這麼簡單的方法,於是去試了一下,果然是Time Limit Exceeded,這個演算法的時間複雜度是O(n^2)。那麼只能想個O(n)的演算法來實現,由於暴力搜尋的方法是遍歷所有的兩個數字的組合,然後算其和,這樣雖然節省了空間,但是時間複雜度高。一般來說,我們為了提高時間的複雜度,需要用空間來換,這算是一個trade off吧,我們只想用線性的時間複雜度來解決問題,那麼就是說只能遍歷一個數字,那麼另一個數字呢,我們可以事先將其儲存起來,使用一個HashMap,來建立數字和其座標位置之間的對映,我們都知道HashMap是常數級的查詢效率,這樣,我們在遍歷陣列的時候,用target減去遍歷到的數字,就是另一個需要的數字了,直接在HashMap中查詢其是否存在即可,注意要判斷查詢到的數字不是第一個數字,比如target是4,遍歷到了一個2,那麼另外一個2不能是之前那個2,整個實現步驟為:先遍歷一遍陣列,建立HashMap對映,然後再遍歷一遍,開始查詢,找到則記錄index。程式碼如下:

 

C++ 解法一:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> m;
        vector<int> res;
        for (int i = 0; i < nums.size(); ++i) {
            m[nums[i]] = i;
        }
        for (int i = 0; i < nums.size(); ++i) {
            int t = target - nums[i];
            if (m.count(t) && m[t] != i) {
                res.push_back(i);
                res.push_back(m[t]);
                break;
            }
        }
        return res;
    }
};

  

Java 解法一:

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> m = new HashMap<Integer, Integer>();
        int[] res = new int[2];
        for (int i = 0; i < nums.length; ++i) {
            m.put(nums[i], i);
        }
        for (int i = 0; i < nums.length; ++i) {
            int t = target - nums[i];
            if (m.containsKey(t) && m.get(t) != i) {
                res[0] = i;
                res[1] = m.get(t);
                break;
            }
        }
        return res;
    }
} 

 

或者我們可以寫的更加簡潔一些,把兩個for迴圈合併成一個:

 

C++ 解法二:

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> m;
        for (int i = 0; i < nums.size(); ++i) {
            if (m.count(target - nums[i])) {
                return {i, m[target - nums[i]]};
            }
            m[nums[i]] = i;
        }
        return {};
    }
};

 

Java 解法二:

public class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> m = new HashMap<Integer, Integer>();
        int[] res = new int[2];
        for (int i = 0; i < nums.length; ++i) {
            if (m.containsKey(target - nums[i])) {
                res[0] = i;
                res[1] = m.get(target - nums[i]);
                break;
            }
            m.put(nums[i], i);
        }
        return res;
    }
}

 

類似題目:

4Sum

3Sum Smaller

3Sum Closest

3Sum

Two Sum III - Data structure design 

Two Sum II - Input array is sorted 

 

參考資料:

https://leetcode.com/problems/two-sum/solution/

https://leetcode.com/problems/two-sum/discuss/3/Accepted-Java-O(n)-Solution

https://leetcode.com/problems/two-sum/discuss/13/Accepted-C++-O(n)-Solution

 

LeetCode All in One 題目講解彙總(持續更新中...)

相關文章