【两数之和】----LeetCode算法题(一)

1、题目基本信息

题目传送门--两数之和数组

级别:【简单】
/**
 * 【两数之和】 给定一个整数数组 nums和一个目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标。
 * 
 * 你能够假设每种输入只会对应一个答案。可是,你不能重复利用这个数组中一样的元素。
 * 
 * 示例:
 * 
 * 给定 nums = [2, 7, 11, 15], target = 9
 * 
 * 由于 nums[0] + nums[1] = 2 + 7 = 9 因此返回 [0, 1]
 * 
 * @Author jiawei huang
 * @Since 2019年8月8日
 * @Version 1.0
 */
复制代码

2、解题思路

  • 一、最简单、最粗暴的方式就是来2层for循环,这种解法时间复杂度为O(n^2) ,不推荐,效率低。bash

  • 二、因为是两数之和等于某一个数,那么咱们很容易就得出一个数学公式A+B=C,咱们作一下变换,获得A=C-B,因为咱们已知的是C,显然等式2比等式1更加容易求值,同时由于变量有两个,小编想到的是咱们一个变量存起来,一个变量进行一次查找比较,所以就有了以下题解思路:ui

    一、遍历一遍数组,而后将每一个值与target作差存起来,同时存该数的下标;spa

    二、直到找到就返回;code

    三、时间复杂度为O(n),空间复杂度也是O(n)leetcode

3、代码演示

【解法一】get

/**
 * 小编本身的解法:9ms
 * 
 * @param nums
 * @param target
 * @return
 */
public static int[] twoSum(int[] nums, int target) {
    int[] returnArr = null;
    
    // 若是数组是空的,或者数组的长度为0,直接返回
    if (null == nums || nums.length == 0) {
    	return returnArr;
    }
    
    Map</* 差值 */Integer, /* 下标 */ Integer> dataMap = new HashMap<>();
    // 既然要知道目标是第几位,不免要知道数组的下标
    for (int i = 0; i < nums.length; i++) {
    	Integer subNum = nums[i];
    	Integer key = target - subNum;
    	if (dataMap.containsKey(subNum)) {
    		// 注意,赋值操做也是耗时的
    		returnArr = new int[2];
    		returnArr[1] = i;
    		returnArr[0] = dataMap.get(subNum);
    	} else {
    		dataMap.put(key, i);
    	}
    }
    
    return returnArr;
}
复制代码

【解法二】数学

/**
 * 针对解法一,小编去除了赋值操做,时间变成6ms
 * 
 * @param nums
 * @param target
 * @return
 */
public static int[] twoSumWithSetValue(int[] nums, int target) {
    // 若是数组是空的,或者数组的长度为0,直接返回
    if (null == nums || nums.length == 0) {
    	return null;
    }
    
    Map</* 差值 */Integer, /* 下标 */ Integer> dataMap = new HashMap<>();
    // 既然要知道目标是第几位,不免要知道数组的下标
    for (int i = 0; i < nums.length; i++) {
    	Integer subNum = nums[i];
    	Integer key = target - subNum;
    	if (dataMap.containsKey(subNum)) {
	    return new int[] { dataMap.get(subNum), i };
    	}
    	dataMap.put(key, i);
    }
    return null;
}
复制代码

【解法三】string

// leetcode大神解法,这解法牛,1ms,但小编没看懂,主要有下面几个疑问,麻烦留言区讨论。
public int[] twoSumOneMs(int[] nums, int target) {
    int indexArrayMax = 2047;
    int[] indexArrays = new int[indexArrayMax + 1];
    int diff = 0;
    for (int i = 0; i < nums.length; i++) {
    	diff = target - nums[i];
    	if (indexArrays[diff & indexArrayMax] != 0) {
    		return new int[] { indexArrays[diff & indexArrayMax] - 1, i };
    	}
    	indexArrays[nums[i] & indexArrayMax] = i + 1;
    }
    throw new IllegalArgumentException("No two sum value");
}
复制代码

这解法牛,耗时仅1ms,但小编没看懂,主要有下面2个疑问,麻烦留言区讨论。it

  • 一、为何数组大小要设置成2048?
  • 二、为何与运算&的数据indexArrayMax要选择成20470111 1111 1111而不是其余值?