[LeetCoding] 1. 两数之和

95 阅读1分钟

Easy

Tag Tag

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

约束条件
  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • Only one valid answer exists.

示例

Example 1:

**Input**: nums = [2,7,11,15], target = 9
**Output**: [0,1]
**Output**: Because nums[0] + nums[1] == 9, we return [0, 1].

Example 2:

**Input:** nums = [3,2,4], target = 6
**Output:** [1,2]

Example 3:

**Input:** nums = [3,3], target = 6
**Output:** [0,1]

题解

本题希望能够在数组中找出和为目标值的两个数的下标。

最简单的方法当然是两层嵌套循环,简单粗暴,但是这种答案显然不能满足认真且好学的我们。

什么?你就喜欢简单粗暴的?可以可以,解法(别说是我写的) 拿去。

题目没有说明数组是不是顺序的,那么我在想如果数组的数字是按顺序排列的会不会比较容易?是的,顺序的数组会有些用处,我们可以利用双指针的方法进行处理,一个指针指向数组起始端,另一个指向末尾端,如果两个指针指向的数的和大于 target,那么就把第二个指针向前移动,如果小于就把第一个指针向后移动,直到等于 target 或者两个指针相遇代表没有答案。看来好像有点意思了,但是我们发现题目要求返回的是两个数的下标,如果对数组进行排序他们的下标就会改变,那么我们可以考虑先把他们的下标保存起来,我们又发现数组里面的数字不一定是唯一的,而且题目要求数组中同一个元素在答案里不能重复出现,我们就需要把相同的数字的下标都保存起来,而且每个下标只能用一次。这个思路没有问题,代码详见解法1

但是我们发现,这个思路下来需要遍历数组两次,而且需要排序操作,好像略微有些麻烦。

细心的我们发现,在第一次遍历的时候我们每次都能得到当前的数字 nums[i] 和已经遍历过的所有数字nums[0], nums[1], ..., nums[i-1],而我们要找存在的 nums[x]+nums[y]=target,那么是不是可以转换为找对任意 nums[i],是否存在 nums[x]=target-nums[i],这不就豁然开朗了,对于 nums[i],我们就找 nums[0], nums[1], ..., nums[i-1] 是不是存在等于 target-nums[i] 的,如果存在就直接返回 itarget-nums[i]对应的下标。那剩下的 nums[i+1], nums[i+1], ..., nums[n] 怎么办?因为如果没找到就会继续往后找,一直到 i=n,所以不用关心后面的数字。按照这个思路可以得到代码解法2,思路极其清晰,代码也简练的许多。

代码

解法(别说是我写的)
class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] result = new int[2];
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] == target) {
                    result[0] = i;
                    result[1] = j;
                    return result;
                }
            }
        }
        return result;
    }
}
解法1
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Stack<Integer>> numIndex = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int num = nums[i];
            if (!numIndex.containsKey(num)) {
                numIndex.put(nums[i], new Stack<Integer>());
            }
            numIndex.get(num).push(i);
        }
        Arrays.sort(nums);
        int lo = 0;
        int hi = nums.length - 1;

        while (lo < hi) {
            if (nums[lo] + nums[hi] > target) {
                hi--;
            } else if (nums[lo] + nums[hi] < target) {
                lo++;
            } else {
                break;
            }
        }
        int[] result = new int[2];
        result[0] = numIndex.get(nums[lo]).pop();
        result[1] = numIndex.get(nums[hi]).pop();
        return result;
    }
}
解法2
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> numIndex = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int left = target - nums[i];
            if (numIndex.containsKey(left)) {
                return new int[]{numIndex.get(left), i};
            } else {
                numIndex.put(nums[i], i);
            }
        }
        return new int[0];
    }
}