我是陈皮,一个在互联网 Coding 的 ITer,个人微信公众号「陈皮的JavaLib」关注第一时间阅读最新文章。

题目

给定一个整数数组 nums 和一个整数目标值 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 <= 10^4

  • -10^9 <= nums[i] <= 10^9

  • -10^9 <= target <= 10^9

解法一

最简单的是暴力法,使用双层循环找出所有两两组合,判断和是否等于目标值。

时间复杂度为 O(n^2) ,空间复杂度为 O(1) 。

package com.chenpi.no0001;

import java.util.Arrays;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/17
 */
public class No0001TwoSum {

  public static void main(String[] args) {
    No0001TwoSum inst = new No0001TwoSum();
    int[] nums = {1, 2, 6, 4, 10, 11, 8, 9};
    int target = 16;
    System.out.println(Arrays.toString(inst.twoSum(nums, target)));
  }

  public int[] twoSum(int[] nums, int target) {

    int length = nums.length;

    for (int i = 0; i < length - 1; i++) {
      for (int j = i + 1; j < length - 1; j++) {
        if (nums[i] + nums[j] == target) {
          return new int[]{i, j};
        }
      }
    }

    return new int[]{};
  }
}

// 输出结果如下
[2, 4]

LeetCode 每日一题「两数之和」_leetcode

解法二

两数之和,即 A+B=SUM 。在已知 SUM 的情况下,然后又知道 A 的值,那么只需要找到一个数 B 等于 SUM - A 即可。

我们只要遍历一遍数组,遍历过的每一个元素值以及它对应下标值,能通过某种规则或者算法(此规则和算法要简单并且存取速度要快)存储起来。后续我们再去查找这个元素的时候能快速查出来,那算法速度就大大提高了。这样只需要遍历一遍数组即可,时间复杂度为 O(N) 。不仅要存取速度快,还能存储对应的数和下标键值对,那就非哈希表莫属了。

时间复杂度为 O(n) ,空间复杂度为 O(n) 。

算法步骤:

  1. 遍历数组每一个数 num,通过 target-num 计算出另一个加数 A ;
  2. 在 map 中查找 key 是否等于 A 的值,如果存在,则返回当前数 num 的下标和 A 的下标;
  3. 如果不存在,则将此数 num 放入map 中,key 为 num,value 为 num 在数组中的下标;
package com.chenpi.no0001;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/17
 */
public class No0001TwoSum {

  public static void main(String[] args) {
    No0001TwoSum inst = new No0001TwoSum();
    int[] nums = {1, 2, 6, 4, 10, 11, 8, 9};
    int target = 16;
    System.out.println(Arrays.toString(inst.twoSum(nums, target)));
  }

  public int[] twoSum(int[] nums, int target) {

    // 记录每一个遍历过的数,利用HashMap插入查找0(1)的高效率时间复杂度
    Map<Integer, Integer> indexMap = new HashMap<>(16);

    // 遍历每一个数
    for (int index = 0; index < nums.length; index++) {
      // target-nums[index]算出另一个加数,然后在map中找有没有这个加数
      if (indexMap.get(target - nums[index]) != null) {
        // 找到了,就返回2个加数的下标
        return new int[]{indexMap.get(target - nums[index]), index};
      } else {
        // 没找到,就将这个数放入map中,key为这个数,value为这个数的下标
        indexMap.put(nums[index], index);
      }
    }
    return null;
  }
}

// 输出结果如下
[2, 4]

LeetCode 每日一题「两数之和」_数组_02

扩展

如果不考虑下标的话,例如只判断是否存在和为目标值的两元素,及其它们的值。其实可以将数组进行排序,然后使用头尾双指针,逐渐靠中间遍历,看是否存在和为目标值的两元素。

遍历一遍数组的时间复杂度为 O(n) ,排序时间复杂度可以为 O(nlogn) ,空间复杂度取决于使用的排序算法。

package com.chenpi.no0001;

import java.util.Arrays;

/**
 * @author 陈皮
 * @version 1.0
 * @description
 * @date 2022/3/17
 */
public class No0001TwoSum {

  public static void main(String[] args) {
    No0001TwoSum inst = new No0001TwoSum();
    int[] nums = {1, 2, 6, 4, 10, 11, 8, 9};
    int target = 16;
    System.out.println(Arrays.toString(inst.twoSum2(nums, target)));
  }

  // 扩展
  public int[] twoSum(int[] nums, int target) {

    // 升序
    Arrays.sort(nums);
    System.out.println(Arrays.toString(nums));
    // 双指针指向头尾
    int left = 0, right = nums.length - 1;
    while (left < right) {
      if (nums[left] + nums[right] == target) {
        // 满足条件
        return new int[]{left, right};
      } else if (nums[left] + nums[right] < target) {
        // 和比目标值小,左指针向右移,让和增大
        left++;
      } else {
        // 和比目标值大,右指针向左移,让和减小
        right--;
      }
    }

    return null;
  }

}

// 输出结果如下
[1, 2, 4, 6, 8, 9, 10, 11]
[3, 6]

本次分享到此结束啦~~

如果觉得文章对你有帮助,点赞、收藏、关注、评论,您的支持就是我创作最大的动力!