leetCode 1 Two Sum

給定一個數組和一個目標和,從陣列中找兩個數字相加等於目標和,輸出這兩個數字的下標。
解法一
簡單粗暴些,兩重迴圈,遍歷所有情況看相加是否等於目標和,如果符合直接輸出。
public int[] twoSum1(int[] nums, int target) { int []ans=new int[2]; for(int i=0;i<nums.length;i++){ for(int j=(i+1);j<nums.length;j++){ if(nums[i]+nums[j]==target){ ans[0]=i; ans[1]=j; return ans; } } } return ans; } 複製程式碼
時間複雜度:兩層 for 迴圈,O(n²)
空間複雜度:O(1)
解法二
在上邊的解法中看下第二個 for 迴圈步驟。
for(int j=(i+1);j<nums.length;j++){ if(nums[i]+nums[j]==target){ 複製程式碼
我們換個理解方式:
for(int j=(i+1);j<nums.length;j++){ sub=target-nums[i] if(nums[j]==sub){ 複製程式碼
第二層 for 迴圈無非是遍歷所有的元素,看哪個元素等於 sub ,時間複雜度為 O(n)。
有沒有一種方法,不用遍歷就可以找到元素裡有沒有等於 sub 的?
hash table !!!
我們可以把陣列的每個元素儲存為 hash 的 key,下標儲存為 hash 的 value 。
這樣只需判斷 sub 在不在 hash 的 key 裡就可以了,而此時的時間複雜度僅為 O(1)!
需要注意的地方是,還需判斷找到的元素不是當前元素,因為題目裡講一個元素只能用一次。
public int[] twoSum2(int[] nums, int target) { Map<Integer,Integer> map=new HashMap<>(); for(int i=0;i<nums.length;i++){ map.put(nums[i],i); } for(int i=0;i<nums.length;i++){ int sub=target-nums[i]; if(map.containsKey(sub)&↦.get(sub)!=i){ return new int[]{i,map.get(sub)}; } } throw new IllegalArgumentException("No two sum solution"); } 複製程式碼
時間複雜度:比解法一少了一個 for 迴圈,降為 O(n)
空間複雜度:所謂的空間換時間,這裡就能體現出來, 開闢了一個 hash table ,空間複雜度變為 O(n)
解法三
看解法二中,兩個 for 迴圈,他們長的一樣,我們當然可以把它合起來。複雜度上不會帶來什麼變化,變化僅僅是不需要判斷是不是當前元素了,因為當前元素還沒有新增進 hash 裡。
public int[] twoSum3(int[] nums, int target) { Map<Integer,Integer> map=new HashMap<>(); for(int i=0;i<nums.length;i++){ int sub=target-nums[i]; if(map.containsKey(sub)){ return new int[]{i,map.get(sub)}; } map.put(nums[i], i); } throw new IllegalArgumentException("No two sum solution"); } 複製程式碼
總結
題目比較簡單,畢竟暴力的方法也可以解決。唯一閃亮的點就是,時間複雜度從 O(n²)降為 O(n) 的時候,對 hash 的應用,有眼前一亮的感覺。