1. 两数之和与回顾哈希表

1. 两数之和

给定一个整数数组 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 <= 103

  • -109 <= nums[i] <= 109

  • -109 <= target <= 109

  • 只会存在一个有效答案

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

方法一:暴力法

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int n = nums.length;    			//定义了变量n,
        for (int i = 0; i < n; ++i) {			//外层循环
            for (int j = i + 1; j < n; ++j) {		//内层循环
                if (nums[i] + nums[j] == target) {	//判断
                    return new int[]{i, j};
                }
            }
        }
        return new int[0];
    }
}

暴力法其实很简单,就是通过枚举遍历整个数组,最坏情况下数组中任意两个数都要被匹配一次。时间复杂度为:

\[O(N^2) \]

其中 N 是数组中的元素数量。

方法二:哈希表法

提到哈希表,我回顾了一下我以前学过的哈希表,简单的总结介绍一下Hash。

哈希表 Hash table也叫散列表。

举个简单的哈希表例子:

有一个数组,数组内的值都在0~10之间,现在要查找数组里是否有key值。我们可以建立一个长度为20的数组默认值为0。把第一个数组内的每一个值都当做第二个数组的下标,每拿一个数,第一个数组对应的第二个下标的值加1,此时可以把key值作为下标来查找第二个数组所对应的值是否不为0,不为0说明数组内有key值。

int a[] = {1, 5,7,3,4,5,1,3,8,0,4,6,1,7};

建立上面这个数组的哈希表:

1 3 0 2 2 2 1 2 1 0
0 1 2 3 4 5 6 7 8 9

此时可以看出时间复杂度为:

\[O(N) \]

同样的这种方法不但可以用来查找,还可以用来排序。如果数组的元素非常多,范围非常小。可以直接建立哈希表,通过哈希表的值来直接进行排序。

当范围不一定的时候,再用以上的方法就不合适了,此时可以根据数组的大小求摸运算。

(关键字)%(数组大小)

例如 12069%7 结果就在0~16之间

又当多次模运算产生的值冲突重复了,可以有多种方法解决比如链表式解决(Separate Chaining)、开方地址(Open Addressing)等,这里简单介绍一下链表式解决。

数据:15 ,22,24, 16

数组大小为:7

哈希函数:下标=关键字 mod 7

先模运算,然后把值放入哈希表中,当15和22的模运算结果重复是,使用链表把15指向22的地址。

image-20210323000350048

哈希表先回顾到这里,回到方法二。

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hashtable = new HashMap<>();
        hashtable.put(nums[0], 0);						//先把第一个值存入哈希表
        //hashmap.put(K key,V value) 这里把原数组的值作为哈希表的下标存入其中,哈希表的值就是原数组的下标。 
        for (int i = 1; i < nums.length; ++i) {			//从第二个数开始
            if (hashtable.containsKey(target - nums[i])){//判断差值是否在哈希表中
                return new int[]{hashtable.get(target - nums[i]), i};//返回两个下标
            }
            hashtable.put(nums[i], i);				//没有就把当前i值存到哈希表中
            //hashmap.get(Object key);这里取的是哈希表的值,前面提到哈希表的值就是原数组的下标。
        }
        return new int[0];
    }
}
posted @ 2021-03-23 00:19  艾德霍华  阅读(153)  评论(0)    收藏  举报