LeetCode刷题笔记-1.两数之和(two-sum)

问题描述

给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。你可以按任意顺序返回答案。

说明

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


示例 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]



题解

1.暴力解法

算法解析

固定一个数,然后寻找满足条件的另一个数.算法主要通过两层循环实现,第一层循环每次固定一个数nums[i],直至遍历完数组.第二层循环从第一层循环固定的那个数的下一个数开始,逐个寻找之后的数nums[j].当发现满足条件nums[i] + nums[j] == target时返回结果.

复杂度分析
  • 时间复杂度: \(O(N^2)\), 两层循环所以时间复杂度为\(O(N^2)\)
  • 空间复杂度: \(O(1)\), 只需要固定的额外空间

代码实现
  • Python版
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        for i in range(n):
            for j in range(i+1, n):
                if nums[i] + nums[j] == target:
                    return [i, j]
        return []


2.哈希表解法

算法解析

由暴力解法可知,两层循环时间复杂度较高.设第一次固定的值为val,如果第二层循环可以通过哈希表直接查询数组中是否存在target - val便可将第二层循环时间复杂度降低到\(O(1)\).该哈希表应该以数组中的值为键,以对应的下标为值构建.这样通过查询是否存在键为target - val的方式便可快速的找到对应值和下标.对于该哈希表的构建方式有两种:

  • 两次遍历,第一次遍历数组先构建哈希表,第二次遍历数组则固定值val查询目标值target - val.
  • 一次遍历,在遍历数组的同时构建哈希表:
    • 先查询表中是否存在与val对应target - val值,有则直接返回结果.
    • 若查询失败,则将当前值val为键,当前下标为值存入哈希表中,以待后面的对应值的查询.
    • 对于遍历第一个元素,由于哈希表为空,自然会将该值及其下标存入哈希表,等待以后查询.
    • 对于重复的两个元素(重复的元素最多为2个)第一个会正常存入哈希表,第二个若为解则会直接返回,不会存入哈希表;若不是解,就算有哈希碰撞也不影响解.

参考文章及资料

LeetCode官方题解 方法二:哈希表
LeetCode精选题解

复杂度分析
  • 时间复杂度: \(O(N)\), 一层循环则时间复杂度为\(O(N)\)
  • 空间复杂度: \(O(N)\), 构建该哈希表的空间复杂度一般为\(O(N)\)

代码实现
  • Python版(两次遍历)
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hash_table = {k: v for v, k in enumerate(nums)}
        for i, value in enumerate(nums):
            search_key = target - value
            # 当存在相同值为解时,由于哈希表存储的是第二个值的下标
            # 而遍历时肯定为第一个值,所以一前一后不会产生冲突
            # 当两个值相同时还需要跳过找到同一个元素的情况
            if search_key in hash_table and i != hash_table[search_key]:
                return [i, hash_table[search_key]]
        return []
  • Java版(一次遍历)
class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer, Integer> hashTable = new HashMap<>();
        for (int i = 0; i < nums.length; ++i) {
            int search_key = target - nums[i];
            // 先查询是否存在与nums[i]对应的值,存在则返回结果
            if (hashTable.containsKey(search_key)) {
                return new int[]{hashTable.get(search_key), i};
            } else { // 不存在时则存入哈希表,以待之后查询
                hashTable.put(nums[i], i);
            }
        }
        return new int[2];   
    }
}



解题误区及心得总结

心得总结
  • 哈希表在保存状态且需要大量查询的时用处很大,也是空间换时间的典型.
  • 本题在遍历数组同时构建哈希表既优化了运行速度又节省了内存,值得学习.
posted @ 2021-01-23 22:05  一生至为你  阅读(162)  评论(0)    收藏  举报