leetcode---两数之和(Ⅰ、Ⅱ)

两数之和Ⅰ

题目描述

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

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

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

实例1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

实例2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

实列3:

输入:nums = [3,3], target = 6
输出:[0,1]

提示

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

思路

所给数组是无序的。因为只有一个答案,所以最笨的方法就是两个for循环。但如果我们用哈希表来解决,会降低时间复杂度。我们用(target - nums[i])来作为key值,i作为value值。因为最后返回的是数组下标。

为什么用(target - nums[i])来作为key值?因为要找两数之和等于target,对于每一个数,它所需要的是(target - num[i]),也就是另一个num[j]的值。如果我们发现哈希表存在num[j],即存在(target - num[i]),那么我们就直接返回value值和j。如果不存在,则把(target - num[i],i)存入到哈希表。

代码

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

两数之和Ⅱ

题目描述

给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。如果设这两个数分别是 numbers[index1] 和 numbers[index2] ,则 1 <= index1 < index2 <= numbers.length 。

以长度为 2 的整数数组 [index1, index2] 的形式返回这两个整数的下标 index1 和 index2。

你可以假设每个输入 只对应唯一的答案 ,而且你 不可以 重复使用相同的元素。

你所设计的解决方案必须只使用常量级的额外空间。

实例1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

实例2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
解释:2 与 4 之和等于目标数 6 。因此 index1 = 1, index2 = 3 。返回 [1, 3] 。

实列3:

输入:numbers = [-1,0], target = -1
输出:[1,2]
解释:-1 与 0 之和等于目标数 -1 。因此 index1 = 1, index2 = 2 。返回 [1, 2] 。

提示

  • 2 <= numbers.length <= 3 * 104
  • -1000 <= numbers[i] <= 1000
  • numbers 按 非递减顺序 排列
  • -1000 <= target <= 1000
  • 仅存在一个有效答案

思路

和上一题不一样,该题数组是非递减顺序排列,这时我们就不需要就用哈希表来操作。对于target = num[i] + num[j](i < j),如果num[i] + num[j] > target,我们希望num[i]小一点或者num[j]小一点。(num[i] + num[j] < target同理)。但这就出现两种情况,到底是num[i]小一点还是num[j]小一点(同理是num[i]大一点还是num[j]大一点)。所以我们需要固定一个,让另一个变化。我们让i从0开始,j从num.length-1开始。这样如果num[i] + num[j] > target,我们能变化的只有num[j],因为num[i]是最小的(非递减num[0]最小),所以我们让num[j]小一点,变成num[j--],以此循环。如果num[i] + num[j] < target,我们能变化的只有num[i],因为num[j]是最大的(非递减num[num.length - 1]最大),所以我们让num[i]大一点,变成num[i++],以此循环。直到我们找到 target = num[i] + num[j]。

代码

public int[] twoSum(int[] num, int target) {
        int len = num.length;
        int start = 0;
        int end = len - 1;
        while(start <= end){
            int sum = num[start] + num[end];
            if(sum == target){
                return new int[]{start + 1, end + 1};
            }else if(sum > target){
                end--;
            }else{
                start++;
            }
        }
        return null;
    }
posted @ 2022-07-07 10:56  littlemelon  阅读(76)  评论(0编辑  收藏  举报