【LeetCode】1、两数之和

题目等级:Two Sum(Easy)

题目描述:

  Given an array of integers, return indices of the two numbers such that they add up to a specific target.

  You may assume that each input would have exactly one solution, and you may not use the same element twice.

  Example:

Given nums = [2, 7, 11, 15], target = 9,Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

  题意:给定一个整数数组和一个指定的数,在数组找两个数使得他们的和等于这个特定数,返回他们的索引,注意一个元素不能重复使用。


解题思路:

  本题实际比较简单,我们给出以下三种解法:

  解法一:暴力法

  这个解法就很直观了,要找两个数使其等于给定的target,两层循环当然是最暴力的解法,时间复杂度是O(n^2),没有使用额外空间,代码如下:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res=new int[]{-1,-1};
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<nums.length;j++){
                if(nums[i]+nums[j]==target){
                    res[0]=i;
                    res[1]=j;
                    break;
                }
            }
        }
        return res;
    }
}

  解法二:HashMap的引入,两遍遍历

  最简单的算法往往并不是最优的,上面的暴力解法用了两层循环,平方的时间复杂度往往不是我们最喜欢的,我们考虑能不能去掉一层循环。也就是说,当给定一个target,给定一个数nums[i],我们能不能不遍历直接找到有没有另一个加数,很明显,只需要判断数组中有没有target-nums[i]即可。

  我们可以将数组中的数保存到hashMap中,借助HashMap的查找优势来解决,将元素值作为key,索引作为value,则常数时间我们就可以判断其中是否有target-nums[i]这个key值。

  唯一需要注意的地方就是同一个元素不能重复使用。由于去掉了一层循环,因此时间复杂度变为O(n),但是这是用一个长度为n的hashmap换来的,空间复杂度为O(n),相当于一种典型的用空间换时间的算法。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int[] res=new int[]{-1,-1};
        Map<Integer,Integer> map=new HashMap<Integer,Integer>();
        for(int i=0;i<nums.length;i++){
            map.put(nums[i],i);
        }
        for(int i=0;i<nums.length;i++){
            if(map.containsKey(target-nums[i]) && map.get(target-nums[i])!=i ){
                res[0]=i;
                res[1]=map.get(target-nums[i]);
                break;
            }
        }
        return res;
    }
}

  解法三:HashMap的改进,一次遍历

  上述解法二,我们可以看到对数组进行了两次遍历,第一次将其存入哈希表,第二次寻找满足条件的元素,实际上这两次循环可以合为一次,即一边存一边寻找满足条件的值。

  当我们遍历到一个元素nums[i]时,可以先判断是否在哈希表中包含target-nums[i],如果存在就相当于已经找到了,不存在则将其加入哈希表,这样做的好处还有一个就是不需要判断是否重复,因为当前元素还没有加入哈希表。

  这和解法二相比实际上是一个微小的改动,时间复杂度和空间复杂度都仍为O(n)。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        /*改进:一遍遍历,利用哈希的查找优势,空间换时间*/
        int[] res=new int[]{-1,-1};
        Map<Integer,Integer> map=new HashMap<>();
        for(int i=0;i<nums.length;i++){
            int another=target-nums[i];
            //注意:num还没有进哈希表,这样可以避免有重复元素的情况
            if(map.containsKey(another)){ //包含target-num,则找到了对应的值
                res[0]=map.get(another); //在哈希表中的是第一个
                res[1]=i;
                break;
            }
            map.put(nums[i],i); //<元素,下标>   
        }
        return res;
    }
}

总结:

  本题实际比较简单。重点就在于利用hashmap的空间来换时间。

原文地址:https://www.cnblogs.com/gzshan/p/10955297.html