LeetCode-Two Sum

题目:https://leetcode.com/problems/two-sum/description/


难度:Easy


题目描述:
给定一个数组,输出两个元素之和等于指定数字的下标,同一个元素不能使用两次。


例如:
Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].


这道题给了我们一个数组,还有一个目标数target,让找到两个数字,使其和为 target,乍一看就感觉可以用暴力搜索,但是猜到 OJ 肯定不会允许用暴力搜索这么简单的方法,于是去试了一下,果然是 Time Limit Exceeded,这个算法的时间复杂度是 O(n^2)。那么只能想个 O(n) 的算法来实现,由于暴力搜索的方法是遍历所有的两个数字的组合,然后算其和,这样虽然节省了空间,但是时间复杂度高。一般来说,为了提高时间的复杂度,需要用空间来换,这算是一个 trade off 吧,但这里只想用线性的时间复杂度来解决问题,就是说只能遍历一个数字,那么另一个数字呢,可以事先将其存储起来,使用一个 HashMap,来建立数字和其坐标位置之间的映射,由于 HashMap 是常数级的查找效率,这样在遍历数组的时候,用 target 减去遍历到的数字,就是另一个需要的数字了,直接在 HashMap 中查找其是否存在即可,注意要判断查找到的数字不是第一个数字,比如 target 是4,遍历到了一个2,那么另外一个2不能是之前那个2,整个实现步骤为:先遍历一遍数组,建立 HashMap 映射,然后再遍历一遍,开始查找,找到则记录 index。或者可以写的更加简洁一些,把两个 for 循环合并成一个



解决方案:
1、暴力遍历数组:

    public static int[] twoSum(int[] nums, int target) {
        int[] a = new int[2];
        if (nums == null) {
            return null;
        }
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {
                if (nums[i] + nums[j] == target) {
                    a[0] = i;
                    a[1] = j;
                }
            }
        }
        return a;
    }

时间复杂度:O(n^2)
空间复杂度:O(1)

2、使用HashMap,nums数组元素为key,下标为value

    public static int[] twoSum(int[] nums, int target) {
        
        Map<Integer, Integer> map = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (map.containsKey(complement)) {
                return new int[] { map.get(complement), i };
            }
            map.put(nums[i], i);
        }
        return null;
    }

时间复杂度:O(n)
空间复杂度:O(n)