1、給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們的數組下標。
你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個數組中同樣的元素。
示例:
1 給定 nums = [2, 7, 11, 15], target = 9 2 3 因爲 nums[0] + nums[1] = 2 + 7 = 9 4 所以返回 [0, 1]
我的答案:
1 package com.leetcode; 2 3 /** 4 * 5 */ 6 public class NumsTarget { 7 8 /** 9 * 給定一個整數數組 nums 和一個目標值 target,請你在該數組中找出和爲目標值的那 兩個 整數,並返回他們的數組下標。 10 * <p> 11 * 你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個數組中同樣的元素。 12 * 13 * @param nums 14 * @param target 15 * @return 16 */ 17 public int[] twoSum(int[] nums, int target) { 18 // 可以定義一個長度爲2的數組 19 int[] resultNums = new int[2]; 20 // 循環遍歷nums的int類型的數組 21 for (int i = 0; i < nums.length; i++) { 22 // 從第i+1的位置開始進行循環遍歷 23 for (int j = i + 1; j < nums.length; j++) { 24 // 判斷,如果第i個位置的數組元素和第i+1個位置的數組元素之和,如果和目標值target相等 25 if (nums[i] + nums[j] == target) { 26 // 就將下標索引的值放到數組中 27 resultNums[0] = i; 28 resultNums[1] = j; 29 } 30 } 31 } 32 // 返回存放索引的數組 33 return resultNums; 34 } 35 36 public static void main(String[] args) { 37 // 定義一個數組,將幾個數組元素添加到數組中 38 int[] nums = new int[]{2, 7, 11, 15}; 39 // 初始化一個目標值 40 int target = 18; 41 42 // 創建一個NumsTarget對象 43 NumsTarget numsTarget = new NumsTarget(); 44 // 調用方法,將參數傳遞進去 45 int[] twoSum = numsTarget.twoSum(nums, target); 46 // 循環遍歷獲取到的索引值元素 47 for (int i = 0; i < twoSum.length; i++) { 48 System.out.println(twoSum[i]); 49 } 50 } 51 52 }
效果截圖:
2、力扣LeetCode給的標準答案。
2.1、方案一,暴力法。暴力法很簡單。遍歷每個元素x,並查找是否存在一個值與target−x相等的目標元素。
1 package com.leetcode; 2 3 /** 4 * 5 */ 6 public class NumsTarget { 7 8 /** 9 * @param nums 10 * @param target 11 * @return 12 */ 13 public int[] twoSum(int[] nums, int target) { 14 // 循環遍歷數組 15 for (int i = 0; i < nums.length; i++) { 16 // 依次遍歷第i+1個值 17 for (int j = i + 1; j < nums.length; j++) { 18 // 如果第i個元素的值和第i+1個元素的值之和等於目標值target。 19 // 或者第i+1個元素的值等於目標值減去第i個元素的值。 20 if (nums[j] == target - nums[i]) { 21 // 返回創建的存儲索引元素值的數組 22 return new int[]{i, j}; 23 } 24 } 25 } 26 // 拋出異常 27 throw new IllegalArgumentException("No two sum solution"); 28 } 29 30 public static void main(String[] args) { 31 // 定義一個數組,將幾個數組元素添加到數組中 32 int[] nums = new int[]{2, 7, 11, 15}; 33 // 初始化一個目標值 34 int target = 18; 35 36 // 創建一個NumsTarget對象 37 NumsTarget numsTarget = new NumsTarget(); 38 // 調用方法,將參數傳遞進去 39 int[] twoSum = numsTarget.twoSum(nums, target); 40 // 循環遍歷獲取到的索引值元素 41 for (int i = 0; i < twoSum.length; i++) { 42 System.out.println(twoSum[i]); 43 } 44 } 45 46 }
方案一,複雜度分析:
1)、時間複雜度:O(n^2),對於每個元素,我們試圖通過遍歷數組的其餘部分來尋找它所對應的目標元素,這將耗費O(n)的時間。因此時間複雜度爲O(n^2)。
2)、空間複雜度:O(1)。
2.2、方案二、兩遍哈希表。
爲了對運行時間複雜度進行優化,我們需要一種更有效的方法來檢查數組中是否存在目標元素。如果存在,我們需要找出它的索引。保持數組中的每個元素與其索引相互對應的最好方法是什麼?哈希表。
通過以空間換取速度的方式,我們可以將查找時間從O(n)降低到 O(1)。哈希表正是爲此目的而構建的,它支持以 近似 恆定的時間進行快速查找。我用“近似”來描述,是因爲一旦出現衝突,查找用時可能會退化到 O(n)。但只要你仔細地挑選哈希函數,在哈希表中進行查找的用時應當被攤銷爲 O(1)。
一個簡單的實現使用了兩次迭代。在第一次迭代中,我們將每個元素的值和它的索引添加到表中。然後,在第二次迭代中,我們將檢查每個元素所對應的目標元素(target−nums[i])是否存在於表中。注意,該目標元素不能是nums[i]本身!
1 package com.leetcode; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 /** 7 * 8 */ 9 public class NumsTarget { 10 11 /** 12 * @param nums 13 * @param target 14 * @return 15 */ 16 public int[] twoSum(int[] nums, int target) { 17 // 創建一個Map集合對象 18 Map<Integer, Integer> map = new HashMap<>(); 19 // 根據數組nums的長度,將所有的數組元素和數據的索引存儲到Map集合中 20 for (int i = 0; i < nums.length; i++) { 21 // key是元素的值,value是索引的值 22 map.put(nums[i], i); 23 } 24 // 循環遍歷數組 25 for (int i = 0; i < nums.length; i++) { 26 // 使用目標值減去數組元素的值 27 int complement = target - nums[i]; 28 // 使用目標值減去數組元素的值,判斷Map集合中是否包含該key的值,並且該key值的value不能等於本身,即不重複 29 if (map.containsKey(complement) && map.get(complement) != i) { 30 // 返回i的值,和包含該complement這個key的value值 31 return new int[]{i, map.get(complement)}; 32 } 33 } 34 throw new IllegalArgumentException("No two sum solution"); 35 } 36 37 public static void main(String[] args) { 38 // 定義一個數組,將幾個數組元素添加到數組中 39 int[] nums = new int[]{2, 7, 11, 15}; 40 // 初始化一個目標值 41 int target = 18; 42 43 // 創建一個NumsTarget對象 44 NumsTarget numsTarget = new NumsTarget(); 45 // 調用方法,將參數傳遞進去 46 int[] twoSum = numsTarget.twoSum(nums, target); 47 // 循環遍歷獲取到的索引值元素 48 for (int i = 0; i < twoSum.length; i++) { 49 System.out.println(twoSum[i]); 50 } 51 } 52 53 }
方案二,複雜度分析:
1)、時間複雜度:O(n),我們把包含有n個元素的列表遍歷兩次。由於哈希表將查找時間縮短到 O(1),所以時間複雜度爲O(n)。
2)、空間複雜度:O(n),所需的額外空間取決於哈希表中存儲的元素數量,該表中存儲了n個元素。
2.3、方案三,一遍哈希表。
事實證明,我們可以一次完成。在進行迭代並將元素插入到表中的同時,我們還會回過頭來檢查表中是否已經存在當前元素所對應的目標元素。如果它存在,那我們已經找到了對應解,並立即將其返回。
1 package com.leetcode; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 /** 7 * 8 */ 9 public class NumsTarget { 10 11 /** 12 * @param nums 13 * @param target 14 * @return 15 */ 16 public int[] twoSum(int[] nums, int target) { 17 // 創建一個Map集合 18 Map<Integer, Integer> map = new HashMap<>(); 19 // 循環遍歷數組 20 for (int i = 0; i < nums.length; i++) { 21 // 使用目標值減去數組元素的值 22 int complement = target - nums[i]; 23 // 判斷Map集合中是否包含該key的值,此算法的精髓所在,將數組元素放入到Map集合中,然後使用使用目標值減去下一個數組元素的值和Map集合中的key值進行判斷 24 if (map.containsKey(complement)) { 25 // 返回i的值,和包含該complement這個key的value值 26 return new int[]{map.get(complement), i}; 27 } 28 // 將數組元素的值和索引值存放到Map集合中 29 map.put(nums[i], i); 30 } 31 throw new IllegalArgumentException("No two sum solution"); 32 } 33 34 public static void main(String[] args) { 35 // 定義一個數組,將幾個數組元素添加到數組中 36 int[] nums = new int[]{2, 7, 11, 15}; 37 // 初始化一個目標值 38 int target = 18; 39 40 // 創建一個NumsTarget對象 41 NumsTarget numsTarget = new NumsTarget(); 42 // 調用方法,將參數傳遞進去 43 int[] twoSum = numsTarget.twoSum(nums, target); 44 // 循環遍歷獲取到的索引值元素 45 for (int i = 0; i < twoSum.length; i++) { 46 System.out.println(twoSum[i]); 47 } 48 } 49 50 }
方案三,複雜度分析:
1)、時間複雜度:O(n),我們只遍歷了包含有n個元素的列表一次。在表中進行的每次查找只花費O(1)的時間。
2)、空間複雜度:O(n),所需的額外空間取決於哈希表中存儲的元素數量,該表最多需要存儲n個元素。
作者:別先生
博客園:https://www.cnblogs.com/biehongli/
如果您想及時得到個人撰寫文章以及著作的消息推送,可以掃描上方二維碼,關注個人公衆號哦。