「算法」从两数之和重新认识哈希数据结构

1,352 阅读2分钟

1. 两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 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]
  1. 首先应明确题目中的数组是否有序,如题目不明确说明,我们一般认为他无序,而无序的情况下除了使用暴力解法,我们考虑使用哈希表,时空复杂度都为O(N)
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        dic = {}
        for i, num in enumerate(nums):
            if target - num in dic:
                return [dic[target - num], i]
            dic[num] = i
        return []
  1. 但是如果题目说明给定一个有序的数组呢?是否有其他优化的方案?答案是肯定的!有序的情况下使用双指针,时间复杂度O(N),空间复杂度O(1)
class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        left, right = 0, len(nums) - 1
        while left < right:
            sum = nums[left] + nums[right]
            if sum == target:
                return [left, right]
            elif sum > target:
                right -= 1
            else:
                left += 1
        return []

771. 宝石与石头

给你一个字符串 jewels 代表石头中宝石的类型,另有一个字符串 stones 代表你拥有的石头。 stones 中每个字符代表了一种你拥有的石头的类型,你想知道你拥有的石头中有多少是宝石。

字母区分大小写,因此 "a" 和 "A" 是不同类型的石头。

示例 1:

输入:jewels = "aA", stones = "aAAbbbb"
输出:3

示例 2:

输入:jewels = "z", stones = "ZZ"
输出:0
  1. 最简单的想法就是利用二重循环来解决,但是这会使时间复杂度达到O(N^2),这是我们极不想看到的。我们考虑用哈希表来解决,在 Python 中有两类重要的哈希结构,利用哈希结构,我们能使判断元素是否在容器中这样的 in 操作的时间复杂度从O(N)降低到O(1),第一类哈希结构是 set,下面的算法时间复杂度为O(M+N),空间复杂度为O(M)
class Solution:
    def numJewelsInStones(self, jewels: str, stones: str) -> int:
        jewelsSet = set(jewels)
        return sum(s in jewelsSet for s in stones)
  1. 第二类哈希结构是 dict,而 Counter 容器是一种高级的 dict,他可以记录每个元素出现的次数,下面的算法时间复杂度为O(M+N),空间复杂度为O(len(set(stones))
class Solution:
    def numJewelsInStones(self, jewels: str, stones: str) -> int:
        counter = Counter(stones)
        return sum(counter[i] for i in jewels)