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; } }
類似題目:
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