你瞭解WeakHashMap嗎
題目:給定一個整數陣列nums和一個目標值target,請你在該陣列中找出和為目標值的那兩個整數,並返回他們的陣列下標。(你可以假設每種輸入只會對應一個答案。但是,陣列中同一個元素不能使用兩遍。)
示例:給定 nums = [2, 7, 11, 15], target = 9,返回 [0, 1],因為 nums[0] + nums[1] = 2 + 7 = 9
方法一:暴力迴圈,時間複雜度O(n²),空間複雜度O(1)
class Solution { public int[] twoSum(int[] nums, int target) {//外層迴圈遍歷陣列,內層迴圈從i+1向後尋找值為target-nums[i]的元素 for (int i = 0; i < nums.length; i++) { for (int j = i + 1; j < nums.length; j++) { if (target - nums[i] == nums[j]) { return new int[]{i, j}; } } }//如果不存在返回一個空的陣列 return new int[0]; } }
方法二:使用雜湊表將時間複雜度降到O(n),空間複雜度也因此變為O(n)。在方法一中,使用外層迴圈時間複雜度為O(n),內層迴圈遍歷查詢值為target-nums[i]的元素,如果這個查詢過程的時間複雜度簡化為O(1),那麼整體的時間複雜度就是O(n)。
class Solution { public int[] twoSum(int[] nums, int target) { HashMap<Integer, Integer> map = newHashMap<>(); for (int i = 0; i < nums.length; i++) { //查詢map中key為target - nums[i]的值,時間複雜度為O(1) if (map.containsKey(target - nums[i])) { return new int[]{map.get(target - nums[i]), i}; } //將當前的nums[i]放入Map,供後面查詢 map.put(nums[i], i); } //如果不存在返回一個空的陣列 return new int[0]; } }
解析:為什麼雜湊表查詢key的時間複雜度是O(1)?
雜湊表也叫散列表,它通過key值計算直接得到儲存在記憶體中的位置,計算的函式就叫雜湊函式,即y=f(key)。就好像根據陣列下標去獲取元素一樣,如果知道了陣列的首地址,那麼其他元素的地址都可以通過下標計算得來,所以用陣列下標獲取陣列元素的時間複雜度是O(1)。而如果只知道元素的值不知道下標,那麼陣列的查詢時間複雜度也是O(n),因為要遍歷陣列進行元素值的比較;而雜湊表相當於直接通過key的值計算得到它的下標位置了,因此時間複雜度為O(1)。
以程式碼中使用的HashMap為例,它的底層採用的是陣列+連結串列+紅黑樹,首先通過key的雜湊值對陣列長度取餘,得到key-value存放在陣列中的位置,如果這個位置已經有其它值了(即發生了雜湊衝突),那麼在當前位置再延伸出一個連結串列繼續存放,再往下為了提高查詢效率又加入了紅黑樹。
總而言之,雜湊表的查詢時間複雜度為O(1)是因為它可以通過key值直接計算得到儲存位置,而不需要去遍歷一個一個比較key值是否相等(時間複雜度為O(n)的方式)。