【leetcode】哈希表刷题tricks

字符串问题

LeetCode242题 有效的字母异位词

class Solution(object):
    def isAnagram(self, s, t):
        d = dict()
        for i in s:
            if i in d:
                d[i] += 1
            else:
                d[i] = 1
        for j in t:
            if j not in d:
                return False
            else:
                d[j] -= 1
        for k, v in d.items():
            if v != 0:
                return False
        return True

 LeetCode49题 字母异位词分组

python的字典可以用元组作为key,可以先对每个字符串的组成字母计数,然后用计数的元组作为key,将相同的字母异位词放在一个组中

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        d = dict()
        for s in strs:
            tmp = [0] * 26
            for i in s:
                tmp[ord(i) - ord('a')] += 1
            d[tuple(tmp)] = d.get(tuple(tmp), []) + [s]
        return list(d.values())

LeetCode205题 同构字符串

需要两个哈希表记录正反两种映射关系

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        k_v = dict()
        v_k = dict()
        for i in range(len(s)):
            if (s[i] in k_v and k_v[s[i]] != t[i]) or (t[i] in v_k and v_k[t[i]] != s[i]):
                return False
            k_v[s[i]] = t[i]
            v_k[t[i]] = s[i]
        return True

 LeetCode1002题 查找共用字符

先统计第一个字符串所有字符出现的次数,放在d中

之后把其他字符串里字符的出现次数也统计出来一次放在tmp_d中

然后用tmp_d更新d,相同的key对应的value取两个哈希表的最小值

最后d中剩的字符数量,就是答案

class Solution:
    def commonChars(self, words: List[str]) -> List[str]:
        res = []
        d = dict()
        for s in words[0]:
            d[s] = d.get(s, 0) + 1
        for w in words[1:]:
            tmp_d = dict()
            for s in w:
                if s in d:
                   tmp_d[s] = tmp_d.get(s, 0) + 1
            for k, v in tmp_d.items():
                tmp_d[k] = min(tmp_d[k], d[k])
            d = tmp_d
        for k, v in d.items():
            res.extend([k] * v)
        return res

 数组问题

LeetCode202题 快乐数

将每一次平方和结果存在哈希表中,如果平方和重复出现,则会无限循环下去,不会是快乐数

class Solution:
    def isHappy(self, n: int) -> bool:
        visited = set()
        while n != 1:
            total = 0
            for i in str(n):
                total += int(i)**2
            if total in visited:
                return False
            visited.add(total)
            n = total
        return True

 LeetCode454题 四数相加II

这道题目是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况,所以相对于四数之和简单了不少,用哈希表就可以解决

class Solution(object):
    def fourSumCount(self, nums1, nums2, nums3, nums4):
        res = 0
        n = len(nums1)
        d1 = dict()
        d2 = dict()
        for i in range(n):
            for j in range(n):
                s1 = nums1[i] + nums2[j]
                s2 = nums3[i] + nums4[j]
                d1[s1] = d1.get(s1, 0) + 1
                d2[s2] = d2.get(s2, 0) + 1
        for k, v in d1.items():
            if -k in d2:
                res += v * d2[-k]
        return res

N数之和问题

LeetCode1题 两数之和

class Solution(object):
    def twoSum(self, nums, target):
        d = dict()
        for i, j in enumerate(nums):
            if target - j in d:
                return [d[target - j], i]
            d[j] = i

LeetCode15题 三数之和

在数组中找到abc使得a + b +c =0,可以排序数组后,固定a = nums[i],然后使用双指针确定bc:b = nums[left],c = nums[right],将复杂度降为O(n^2)

双指针移动方法:如果nums[i] + nums[left] + nums[right] > 0,说明三数之和大了,right就向左移动;如果nums[i] + nums[left] + nums[right] < 0,说明三数之和小了,left就向右移动;直到left与right相遇为止

去重:主要考虑abc三个数的去重。对于a的去重,如果nums[i]与nums[i-1]相同,则跳过对应的i;对于bc的去重,需要在收集到结果后,移动left、right指针,将重复的bc去掉

class Solution(object):
    def threeSum(self, nums):
        res = []
        nums.sort()
        for i in range(len(nums)):
            # 剪枝
            if nums[i] > 0:
                return res
            # 去重
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            left = i + 1
            right = len(nums) - 1
            while left < right:
                if nums[i] + nums[left] + nums[right] > 0:
                    right -= 1
                elif nums[i] + nums[left] + nums[right] < 0:
                    left += 1
                else:
                    res.append([nums[i], nums[left], nums[right]])
                    left += 1
                    right -= 1
                    # 去重
                    while left < right and nums[left] == nums[left - 1]:
                        left += 1
                    while left < right and nums[right] == nums[right + 1]:
                        right -= 1
        return res

LeetCode18题 四数之和

和三数之和思路相同,四数之和的双指针解法是两层for循环nums[i] + nums[j]为确定值,然后循环内有left和right下标作为双指针,找出nums[i] + nums[j] + nums[left] + nums[right] == target的情况,四数之和的时间复杂度是O(n^3) 

class Solution(object):
    def fourSum(self, nums, target):
        n = len(nums)
        res = []
        if n < 4:
            return res
        nums.sort()
        for i in range(n):
            # 剪枝
            if nums[i] > 0 and nums[i] > target:
                return res
            # 去重
            if i - 1 >= 0 and nums[i] == nums[i - 1]:
                continue
            for j in range(i + 1, n):
                # 剪枝
                if nums[i] + nums[j] > 0 and nums[i] + nums[j] > target:
                    break
                # 去重
                if j - 1 >= i + 1 and nums[j] == nums[j - 1]:
                    continue
                left = j + 1
                right = n - 1
                while left < right:
                    sum_ = nums[i] + nums[j] + nums[left] + nums[right]
                    if sum_ > target:
                        right -= 1
                    elif sum_ < target:
                        left += 1
                    else:
                        res.append([nums[i], nums[j], nums[left], nums[right]])
                        right -= 1
                        left += 1
                        # 去重
                        while left < right and nums[left] == nums[left - 1]:
                            left += 1
                        while left < right and nums[right] == nums[right + 1]:
                            right -= 1
        return res

数据结构设计

LeetCode380题 O(1)时间插入、删除和获取随机元素

如果想高效地,等概率地随机获取元素,就要使用数组作为底层容器

可以使用数组记录元素,使用哈希表记录val和数组索引的映射关系。删除元素时,为了保持数组元素的紧凑性,先将要删除的元素和数组末尾元素交换位置,然后将数组最后一个元素删除即可

class RandomizedSet:

    def __init__(self):
        self.nums = []
        self.val_to_index = {}

    def insert(self, val: int) -> bool:
        if val not in self.val_to_index:
            self.nums.append(val)
            self.val_to_index[val] = len(self.nums) - 1
            return True
        else:
            return False

    def remove(self, val: int) -> bool:
        if val in self.val_to_index:
            i1, i2 = self.val_to_index[val], len(self.nums) - 1
            if i1 != i2:
                self.val_to_index[self.nums[i2]] = i1
                self.nums[i1], self.nums[i2] = self.nums[i2], self.nums[i1]
            self.nums.pop()
            del self.val_to_index[val]
            return True
        else:
            return False

    def getRandom(self) -> int:
        import random
        i = random.randint(0, len(self.nums) - 1)
        return self.nums[i]

LeetCode710题 黑名单中的随机数

思路类似380题,对于区间[0, n - len(blacklist) - 1]中的黑名单数,需要找到他们和区间[n - len(blacklist), n - 1]中非黑名单数的一个映射。然后可以在区间[0, n - len(blacklist) - 1]选一个随机数,如果这个数在黑名单中,我们就取它映射的那个数,如果不在黑名单,直接把这个数作为结果

import random
class Solution:

    def __init__(self, n: int, blacklist: List[int]):
        self.size = n - len(blacklist)
        self.hash_map = dict()
        last = n - 1
        for i in blacklist:
            self.hash_map[i] = i
        for i in blacklist:
            # 剪枝,若i >= self.size,此时没必要找到黑名单数字的映射关系
            if i >= self.size:
                continue
            while last in self.hash_map:
                last -= 1
            self.hash_map[i] = last
            last -= 1

    def pick(self) -> int:
        r = random.randint(0, self.size - 1)
        if r in self.hash_map:
            return self.hash_map[r]
        else:
            return r
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值