给定一个整数数组 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%的用户,嗯,看来效果确实很显著。
若是你有更好的想法,也欢迎留言交流讨论~