給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那兩個整數,並返回他們的數組下標。java
你能夠假設每種輸入只會對應一個答案。可是,你不能重複利用這個數組中一樣的元素。算法
示例:數組
給定 nums = [2, 7, 11, 15], target = 9 由於 nums[0] + nums[1] = 2 + 7 = 9 因此返回 [0, 1]
從題目意思理解,就是從給定的整數數組中找到兩個整數,使得它們的和與給定的數相等。那最簡單粗暴的方式就是枚舉了,嗯,先來試試最簡單的。bash
class Solution { public int[] twoSum(int[] nums, int target) { return exhaustAlgorithm(nums,target); } // 窮舉法 private int[] exhaustAlgorithm(int[] nums, int target){ int length = nums.length; int i = 0; int j = 1; while (nums[i] + nums[j] != target) { j++; if (j >= length){ i++; if (i >= length - 1){ break; } j = i + 1; } } // 說明不存在這樣的組合 if (nums[i] + nums[j] != target) return null; int[] result = {i,j}; return result; } }
時間複雜度:\(O(n^2)\)優化
運行結果以下:spa
80ms,才擊敗了11.13%的用戶,說明優化空間還很大。code
窮舉法的效率通常都比較差,因此須要嘗試一些新姿式。咱們再來分析一下上面的窮舉算法,要從一個集合中找出兩個數,使得它們的和與給出的數target
相等,使用窮舉算法時,當咱們選出第一個數a
後,須要循環遍歷以後的數,而後一一進行加和判斷,但實際上,咱們只須要知道剩下的數裏,有沒有數等於target - a
便可,而每次從數組中找到某個數是否存在,都須要遍歷一次,所以,更好的作法是將數與對應的序號存到一個map中,這樣就能將查找效率從\(O(n)\)提升到\(O(1)\)。blog
class Solution { public int[] twoSum(int[] nums, int target) { return mapSolution(nums,target); } // 倒推法 private int[] mapSolution(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 num = target - nums[i]; // 判斷num是否存在,若是已經存在,則直接返回 if (map.get(num) != null){ return new int[] { map.get(num), i}; } } return null; } }
這裏咱們對nums數組進行了兩次遍歷,第一次遍歷是將全部元素都存入map中,第二次遍歷是查找目標的整數對是否存在。leetcode
但再仔細想一想,是否還能再優化呢?get
答案是確定的,在這個題中,要尋找的整數是成對存在的,因此咱們能夠只進行一次遍歷。
若是target
減去當前遍歷數值後的數不存在於map
中,則將當前數值與序號的映射關係存入map
中。也許你會問,那找到第一個要尋找的數時,第二個數顯然還不在map
中,那怎麼辦呢?彆着急,前面已經說過了,由於要尋找的數是成對存在的,這裏咱們假設爲a
和b
,因此遇到第一個數a
時,因爲b
尚未存入map
,因此先將a
存入map
中,咱們在找到第二個數b
後,此時a
已經在map
中了,因此就能在一次遍歷中順利找到了這對咱們想要的整數了。
class Solution { public int[] twoSum(int[] nums, int target) { return mapSolution(nums,target); } // 倒推法 private int[] mapSolution(int[] nums, int target){ Map<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++){ int num = target - nums[i]; // 判斷num是否存在,若是已經存在,則直接返回 if (map.get(num) != null){ return new int[] { map.get(num), i}; } // 不存在則當前數值與序號的映射關係存入map中 map.put(nums[i], i); } return null; } }
時間複雜度:\(O(n)\)
空間複雜度:\(O(n)\)
運行結果以下:
一降低到了9ms,效率大大提高,擊敗85%的用戶,嗯,看來效果確實很顯著。
若是你有更好的想法,也歡迎留言交流討論~