Leetcode刷题笔记——哈希表篇

Leetcode刷题笔记——哈希表篇

一、哈希表在面试中的高频考题

第一题:两数之和

Leetcode1:两数之和:中等题 (详情点击链接见原题)

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标

python代码解法

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        hash_table = {}
        for index, value in enumerate(nums):
            if target - value in hash_table:
                return [index, hash_table[target - value]]
            hash_table[value] = index   # 以nums数组的value为key,index为value
        return []

第二题:同构字符串

Leetcode205:同构字符串:简单题 (详情点击链接见原题)

给定两个字符串 st ,判断它们是否是同构的。
如果 s 中的字符可以按某种映射关系替换得到 t ,那么这两个字符串是同构的

解题思路

相同的字符只能映射到同一个字符上,不同字符不能映射到同一个字符上
st 之间是 双射, 满足一一对应,考虑遍历字符串,使用哈希表 s_to_tt_to_s 分别记录 s—>tt—>s 的映射,当发现任意不满足一对一的关系时返回 False 即可
python代码解法

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        if len(s) != len(t):
            return False
        s_to_t = {}
        t_to_s = {}
        for i in range(len(s)):
            if s[i] not in s_to_t:
                s_to_t[s[i]] = t[i]
            if t[i] not in t_to_s:
                t_to_s[t[i]] = s[i]
            if s_to_t[s[i]] != t[i] or t_to_s[t[i]] != s[i]:
                return False
        return True

第三题:单词规律

Leetcode290. 单词规律:简单题 (详情点击链接见原题)

给定一种规律 pattern 和一个字符串 s ,判断 s 是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律

python代码解法

class Solution:
    def wordPattern(self, pattern: str, s: str) -> bool:
        words = s.split()
        if len(pattern) != len(words):
            return False
        s_p = {}
        p_s = {}
        for char, word in zip(pattern, words):
            if (char in p_s and p_s[char] != word) or (word in s_p and s_p[word] != char):
                return False
            p_s[char] = word
            s_p[word] = char
        return True

第三题:两个数组的交集

Leetcode349:两个数组的交集:简单题 (详情点击链接见原题)

给定两个数组 nums1nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序

python代码解法1

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        common = {}
        for i in nums1:
            common[i] = common.get(i, 0) + 1

        res = []
        for j in nums2:
            if j in common and j not in res:
                res.append(j)
        return res

python代码解法2

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        nums1_lis = [0] * 1001
        nums2_lis = [0] * 1001

        for i in nums1:
            nums1_lis[i] = 1
        for j in nums2:
            nums2_lis[j] = 1

        res = []
        for i in range(1001):
            if nums2_lis[i] * nums1_lis[i]:
               res.append(i)
        return res

第四题:数组的度

Leetcode697. 数组的度:简单题 (详情点击链接见原题)

给定一个非空且只包含非负数的整数数组 nums,数组的 度 的定义是指数组里任一元素出现频数的最大值

python代码解法1

class Solution:
    def findShortestSubArray(self, nums: List[int]) -> int:
        count_1 = [0] * 50000
        count_2 = [0] * 50000
        for i in nums:
            count_1[i] += 1
        max_fre = max(count_1)
        left, right = 0, 0
        min_len = float('inf')
        while right < len(nums):
            count_2[nums[right]] += 1
            while count_2[nums[right]] == max_fre:
                if count_2[nums[left]] == max_fre:
                    min_len = min(min_len, right - left + 1)
                count_2[nums[left]] -= 1
                left += 1
            right += 1
        return min_len

第五题:赎金信

Leetcode383. 赎金信:简单题 (详情点击链接见原题)

给你两个字符串:ransomNotemagazine ,判断 ransomNote 能不能由 magazine 里面的字符构成

python代码解法

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        char_map = [0] * 26
        for r in ransomNote:
            char_map[ord(r) - ord('a')] += 1
        for m in magazine:
            char_map[ord(m) - ord('a')] -= 1
        for r in ransomNote:
            if char_map[ord(r) - ord('a')] > 0:
                return False
        return True

第六题:快乐数

Leetcode202. 快乐数:中等题 (详情点击链接见原题)

编写一个算法来判断一个数 n 是不是快乐数,如果 n 是 快乐数 就返回 true ;不是,则返回 false

解题思路
题目中说了会无限循环,那么也就是说求和过程中,sum会重复出现,这对题解很重要,当我们遇到了要快速判断一个元素是否出现集合里的时候就要考虑哈希法了

python代码解法

class Solution:
    def bitSum(self, n):
        res = 0
        while n > 0:
            temp = n % 10
            res += temp ** 2
            n //= 10
        return res

    def isHappy(self, n: int) -> bool:
        hash_map = []

        while n:
            n = self.bitSum(n)
            hash_map.append(n)
            if self.bitSum(n) in hash_map:
                if n == 1:
                    return True
                else:
                    return False

附上另一种解题思路,快慢指针法
python代码解法2

class Solution:
    def bitSquareSum(self, n):
        total = 0
        while n > 0:
            bit = n % 10
            total += bit ** 2
            n //= 10
        return total

    def isHappy(self, n: int) -> bool:
        slow, fast = n, n
        while self.bitSquareSum(fast) != 1 and self.bitSquareSum(self.bitSquareSum(fast)):
            slow = self.bitSquareSum(slow)
            fast = self.bitSquareSum(fast)
            fast = self.bitSquareSum(fast)
            if slow == fast:
                return False
        return True

第七题:有效的字母异位词

Leetcode242. 有效的字母异位词:中等题 (详情点击链接见原题)

利用数组作为映射字母和对应字母的出现次数的映射关系
python代码解法

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        char_map = [0] * 26
        if len(s) != len(t):
            return False
        for index, value in enumerate(s):
            char_map[ord(value) - ord('a')] += 1
            char_map[ord(t[index]) - ord('a')] -= 1

        for j in char_map:
            if j != 0:
                return False
        return True

第八题:字母异位词分组

Leetcode49:字母异位词分组:中等题 (详情点击链接见原题)

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表

python代码解法1

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        hash_table = {}
        for st in strs:
            key = "".join(sorted(st))
            if key not in hash_table:
                hash_table[key] = [st]
            else:
                hash_table[key].append(st)
        return list(hash_table.values())

python代码解法2

class Solution:
    def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        hash_table = {}
        for st in strs:
            char_map = [0] * 26
            for i in range(0, len(st)):
                char_map[ord(st[i]) - ord('a')] += 1

            key = "-".join(str(i) for i in char_map)    # 保证键的唯一性
            print(key)
            if key not in hash_table:
                hash_table[key] = [st]
            else:
                hash_table[key].append(st)
        return list(hash_table.values())

第九题:连接两字母单词得到的最长回文串

Leetcode2131. 连接两字母单词得到的最长回文串:中等题 (详情点击链接见原题)

给你一个字符串数组 wordswords 中每个元素都是一个包含 两个 小写英文字母的单词

方法1:用二维数组代替哈希
python代码解法

class Solution:
    def longestPalindrome(self, words: List[str]) -> int:
        char_map = [[0] * 26 for _ in range(26)]
        palindromeLen = 0
        for word in words:
            c1 = ord(word[0]) - ord('a')
            c2 = ord(word[1]) - ord('a')
            if char_map[c2][c1] > 0:
                char_map[c2][c1] -= 1
                palindromeLen += 4
                continue
            char_map[c1][c2] += 1

        for i in range(26):
            if char_map[i][i] > 0:
                palindromeLen += 2
                break
        return palindromeLen

方法2:类似于两数之和的解题思想

from typing import List
from collections import Counter

class Solution:
    def longestPalindrome(self, words: List[str]) -> int:
        word_map = Counter()
        palindromeLen = 0
        for word in words:
            word_reverse = word[::-1]
            if word_map[word_reverse] > 0:
                word_map[word_reverse] -= 1
                palindromeLen += 4  # 匹配成功,可以添加到最长回文串的两端
                continue
            else:
                word_map[word] += 1

        for word, value in word_map.items():
            if word[0] == word[1] and value > 0:
                palindromeLen += 2
                break
        return palindromeLen

第十题:最长和谐子序列

Leetcode594. 最长和谐子序列:简单题 (详情点击链接见原题)

和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1
现在,给你一个整数数组 nums ,请你在所有可能的子序列中找到最长的和谐子序列的长度

我们可以通过哈希表记录所有的 nums[i] 的出现次数,然后通过 O(n)的复杂度找出所有可能的对数(两数差值为 1)并在所有符合条件的数对所能构成的 和谐子序列 长度中取最大值
python代码解法

from collections import Counter


class Solution:
    def findLHS(self, nums: List[int]) -> int:
        if len(nums) <= 1:
            return 0
        hash_map = Counter(nums)
        ans = 0
        nums.sort()
        for i in nums[1:]:
            if i - 1 in hash_map:
                ans = max(ans, hash_map[i] + hash_map[i - 1])
        return ans

第十一题:丢失的数字

Leetcode268. 丢失的数字:简单题 (详情点击链接见原题)

给定一个包含 [0, n]n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数

原地哈希
我们可以将 nums本身作为哈希表使用,将 nums[i] 放到其应该出现的位置上

python代码解法

class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        def swap(arr, i, j):
            temp = arr[i]
            arr[i] = arr[j]
            arr[j] = temp

        n = len(nums)
        for i in range(0, n):
            while nums[i] != i and nums[i] < n:
                swap(nums, i, nums[i])

        for i in range(0, n):
            if i != nums[i]:
                return i
        return n

第十二题:缺失的第一个正数

Leetcode41. 缺失的第一个正数:困难题 (详情点击链接见原题)

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案

题目要求我们只能使用常数级别的空间,而要找的数一定在 [1, N + 1] (左闭右闭) 这个区间里,因此我们可以就把原始的数组当作哈希表来使用,我们要找的数就在 [1, N + 1] 里,最后 N + 1 这个元素我们不用找,因为在前面的 N 个元素都找不到的情况下我们才返回 N + 1
解题思路:
把数值为 i 的数映射到 下标为 i - 1 的位置,理解下面代码 nums[nums[i] - 1] != nums[i] 的作用,在 nums[i] 的范围是合法区间的前提下,我们就将 nums[i] 映射到它原本应在的位置上去

python代码解法

class Solution:
    def swap(self, nums, a, b):
        temp = nums[a]
        nums[a] = nums[b]
        nums[b] = temp

    def firstMissingPositive(self, nums: List[int]) -> int:
        n = len(nums)
        for i in range(n):
            while 1 <= nums[i] <= n and nums[i] != nums[nums[i] - 1]:
                self.swap(nums, i, nums[i] - 1)

        for i in range(n):
            if i + 1 != nums[i]:
                return i + 1
        return n + 1

第十三题:查找共用字符

Leetcode1002. 查找共用字符:简单题 (详情点击链接见原题)

给你一个字符串数组 words ,请你找出所有在 words 的每个字符串中都出现的共用字符( 包括重复字符),并以数组形式返回。你可以按 任意顺序 返回答案

解题思路:用二维数组代替哈希映射

python代码解法

class Solution:
    def commonChars(self, words: List[str]) -> List[str]:
        char_map = [[0 for _ in range(26)] for _ in range(len(words))]
        for r in range(len(words)):
            for c in range(len(words[r])):
                char_map[r][ord(words[r][c]) - ord('a')] += 1
        ans = []

        for y in range(len(char_map[0])):
            min_v = sys.maxsize
            for x in range(len(char_map)):
                min_v = min(min_v, char_map[x][y])
            for _ in range(min_v):
                ans.append(chr(ord('a') + y))
        return ans

二、哈希表在前缀和中的应用

第一题 :和为 K 的子数组

Leetcode560. 和为 K 的子数组:中等题 (详情点击链接见原题)

给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数

python代码解法1

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        sum_prefix = {0: 1}  # 记录第一个和为k的数组
        cur_num = 0
        result = 0
        for num in nums:
            cur_num += num
            if cur_num - k in sum_prefix:
                result += sum_prefix[cur_num - k]  # 中间出现连续0的情况
            sum_prefix[cur_num] = sum_prefix.get(cur_num, 0) + 1
        return result

第二题:砖墙

Leetcode554:砖墙:中等题 (详情点击链接见原题)

你的面前有一堵矩形的、由 n 行砖块组成的砖墙。这些砖块高度相同(也就是一个单位高)但是宽度不同。每一行砖块的宽度之和相等。

我们可以使用【哈希表】记录每个间隙出现的次数,最终统计所有行中哪些间隙出现得最多,使用 总行数 减去 间隙出现的最多次数 即是答案

如何记录间隙呢?
直接使用行前缀和记录即可
python代码解法

class Solution:
    def leastBricks(self, wall: List[List[int]]) -> int:
        count = Counter()
        for w in wall:
            cur_sum = 0
            for i in w:
                cur_sum += i
                count[cur_sum] += 1
            count.pop(cur_sum)   # 不能从两边穿过,需要 remove 掉最后一个
        max_gap = 0
        for k in count:  # 求最少穿过的砖块数,即找出间隙号最多的间隙数
            max_gap = max(max_gap, count[k])
        return len(wall) - max_gap

三、哈希结构的设计

第一题 :设计哈希集合

Leetcode705.设计哈希集合:中等题 (详情点击链接见原题)

不使用任何内建的哈希表库设计一个哈希集合(HashSet)

HashSet是在时间和空间上做权衡的经典案例,如果不考虑空间,我们可以设计一个超大的数组,使每个key都有单独的位置,则不存在冲突

设计哈希函数需要考虑的两个问题:

  1. 通过 hash 方法把键 key 转成数组的索引,设计合适的 hash 函数,一般都是对分桶数取模 %
  2. 处理碰撞冲突问题:拉链法和线性探测法

拉链法是说我们定义了一个比较小的数组,然后用hash方法来求出 key 应该出现在数组中的位置,但是由于不同的 key 在求完 hash 之后可能会存在碰撞冲突,所以数组并不直接保存元素,而是每个位置都指向了一条链表(数组)用于存储元素

分桶数组:其实是拉链法的变形
大家别被这个陌生的专业名词吓到,其实很简单

python代码解法1

class MyHashSet:

    def __init__(self):
        self.buckets = 1000		# 1000个桶
        self.itemsPerBucket = 1001  # 每个桶中预留1001个位置
        self.table = [[] for _ in range(self.buckets)]

    def add(self, key: int) -> None:
        pos = key // self.buckets  # 先确定桶中的具体位置(后面会用到)
        key %= self.buckets		# 确定key所在哪个桶中(因为这里会改变 key 值,所以 pos 放到前面计算)
        if not self.table[key]:
            self.table[key] = [0] * self.itemsPerBucket
        self.table[key][pos] = 1

    def remove(self, key: int) -> None:
        pos = key // self.buckets   # 先确定桶中的具体位置
        key %= self.buckets        # 确定key所在哪个桶中
        if not self.table[key]:
            return
        if self.table[key][pos]:
            self.table[key][pos] = 0

    def contains(self, key: int) -> bool:
        pos = key // self.buckets     # 先确定桶中的具体位置
        key %= self.buckets           # 确定key所在哪个桶中
        if not self.table[key]:
            return False
        return True if self.table[key][pos] else False

# Your MyHashSet object will be instantiated and called as such:
# obj = MyHashSet()
# obj.add(2)
# obj.remove(2)
# obj.remove(5)
# param_3 = obj.contains(2)
# print(param_3)

真正的拉链法:用链表实现的拉链法
python代码解法2

class ListNode:
    def __init__(self, val=None, next=None):
        self.val = val
        self.next = next


class MyHashSet:
    def __init__(self):
        self.size = 1000
        self.linklist = [ListNode() for _ in range(self.size)]

    def add(self, key: int) -> None:
        value = key
        key %= self.size
        p = self.linklist[key]
        temp = p
        while temp:
            if temp.val == value:
                return
            temp = temp.next
        pre = ListNode(value)
        pre.next = p.next
        p.next = pre

    def remove(self, key: int) -> None:
        value = key
        key %= self.size
        p = self.linklist[key]
        pre = p
        temp = p.next
        while temp:
            if temp.val == value:
                pre.next = temp.next
            pre = pre.next
            temp = temp.next

    def contains(self, key: int) -> bool:
        value = key
        key %= self.size
        p = self.linklist[key]
        temp = p
        while temp:
            if temp.val == value:
                return True
            temp = temp.next
        return False

第二题: LRU 缓存

Leetcode146. LRU 缓存:中等题 (详情点击链接见原题)

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构

python代码解法

class ListNode:
    def __init__(self, key=None, value=None):
        self.key = key
        self.value = value
        self.prev = None
        self.next = None


class LRUCache:

    def __init__(self, capacity: int):
        self.capacity = capacity
        self.hash_map = {}
        self.head, self.tail = ListNode(), ListNode()
        self.head.next = self.tail
        self.tail.prev = self.head

    def move_to_head(self, key):
        """
        即双链表的一个查找和插入操作
        :param key:
        :return:
        """
        node = self.hash_map[key]   # 找到 key 对应的结点

		# 将该节点与原链表断链
        node.prev.next = node.next
        node.next.prev = node.prev

        # 将最近访问的节点放到头结点后
        node.next = self.head.next
        node.prev = self.head.next.prev
        self.head.next.prev = node
        self.head.next = node

    def get(self, key: int) -> int:
        if key in self.hash_map:   # 如果关键字 key 已经存在
            self.move_to_head(key)   # 将该 key 对应的结点插入到头结点后更新为最近访问
        return -1 if self.hash_map.get(key, -1) == -1 else self.hash_map[key].value   # 返回关键字对应的值

    def put(self, key: int, value: int) -> None:
        if key in self.hash_map:   # 如果要插入结点的 key 已存在
            self.hash_map[key].value = value   # 变更其数据值
            self.move_to_head(key)     # 将该 key 对应的结点插入到头结点后更新为最近访问
        else:
            if len(self.hash_map) == self.capacity:  # 如果容量已满,去掉最久没有被访问的节点
                self.hash_map.pop(self.tail.prev.key)  # 去掉尾节点的前一个节点(最久未使用)
                self.tail.prev.prev.next = self.tail
                self.tail.prev = self.tail.prev.prev
            new_node = ListNode(key, value)   # 申请一个新结点
            self.hash_map[key] = new_node     # 将该结点与哈希表中的key建立映射关系
			
			# 将新结点插入到头结点之后
            new_node.next = self.head.next
            new_node.prev = self.head.next.prev
            self.head.next.prev = new_node
            self.head.next = new_node

四、哈希表在滑动窗口中的应用

第一题:无重复字符的最长子串

Leetcode3. 无重复字符的最长子串:中等题 (详情点击链接见原题)

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度

python代码解法

from collections import Counter


class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        max_len = 0
        slide_window = Counter()  # 统计滑动窗口内不同元素的数目
        left, right = 0, 0
        while right < len(s):
            slide_window[s[right]] += 1
            while slide_window[s[right]] > 1:
                slide_window[s[left]] -= 1
                left += 1
            right += 1
            max_len = max(max_len, right - left)
        return max_len

五、哈希表的其他应用

第一题:最长连续序列

Leetcode128. 最长连续序列:中等题 (详情点击链接见原题)

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度

hash_dict = {key :value}

这里的 key 很好理解,就是 nums 里的每一个元素,关键是 value 的定义,【哈希表存储每个端点值对应连续区间的长度】

python代码解法

class Solution:
    def longestConsecutive(self, nums: List[int]) -> int:
        hash_map = {}
        max_len = 0
        for num in nums:
            if num not in hash_map:
                left = hash_map.get(num - 1, 0)
                right = hash_map.get(num + 1, 0)
                cur_len = 1 + left + right
                max_len = max(max_len, cur_len)
                hash_map[num] = cur_len
                hash_map[num - left] = cur_len
                hash_map[num + right] = cur_len
        return max_len

第二题:匹配子序列的单词数

Leetcode792. 匹配子序列的单词数:中等题 (详情点击链接见原题)

给定字符串 s 和字符串数组 words, 返回 words[i] 中是 s 的子序列的单词个数

解题思路
words 中的所有单词根据首字母来分桶,即把所有单词按照首字母分到26个桶中,每个桶中存储的是以该字母开头的所有单词,然后我们从 s 的第一个字符开始遍历,假设当前字符为 a,我们从 a 开头的桶中取出所有单词,如果此时单词长度为 1,说明该单词已经匹配完毕,我们将答案 +1,否则我们将单词的首字母去掉,然后放如下一个字母开头的桶中

python代码解法

from collections import defaultdict, deque


class Solution:
    def numMatchingSubseq(self, s: str, words: List[str]) -> int:
        hash_map = defaultdict(deque)
        for w in words:
            hash_map[w[0]].append(w)
        ans = 0
        for c in s:
            for _ in range(len(hash_map[c])):
                t = hash_map[c].popleft()
                if len(t) == 1:
                    ans += 1
                else:
                    hash_map[t[1]].append(t[1:])
        return ans

第三题:罗马数字转整数

Leetcode13. 罗马数字转整数:简单题 (详情点击链接见原题)

罗马数字包含以下七种字符: IVXLCDM

python代码解法

class Solution:
    def romanToInt(self, s: str) -> int:
        char_map = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
        pre = char_map[s[0]]
        ans = 0
        for i in range(1, len(s)):
            cur = char_map[s[i]]
            if cur <= pre:
                ans += pre
            else:
                ans -= pre
            pre = cur
        ans += pre
        return ans

第四题:文物朝代判断

LCR186. 文物朝代判断:简单题 (详情点击链接见原题)

展览馆展出来自 13 个朝代的文物,每排展柜展出 5 个文物。某排文物的摆放情况记录于数组 places,其中 places[i] 表示处于第 i 位文物的所属朝代编号。其中,编号为 0 的朝代表示未知朝代。请判断并返回这排文物的所属朝代编号是否连续(如遇未知朝代可算作连续情况)

解题思路

  1. 除未知朝代外,所有朝代无重复
  2. 未知朝代 0 可以代替任何牌
  3. 设此 5 个朝代中最大的为 max_v,最小的朝代为 min_v,未知朝代除外,则需满足 max_v - min_v < 5

python代码解法

class Solution:
    def checkDynasty(self, places: List[int]) -> bool:
        repeat = {}
        max_v, min_v = 0, 14
        for place in places:
            if place == 0:
                continue
            max_v = max(max_v, place)
            min_v = min(min_v, place)
            if place in repeat:
                return False
            repeat[place] = 1
        return max_v - min_v < 5

六、哈希表在排序中的应用

第一题:自定义字符串排序

Leetcode791. 自定义字符串排序:中等题 (详情点击链接见原题)

给定两个字符串 ordersorder 的所有字母都是 唯一 的,并且以前按照一些自定义的顺序排序

起始先用大小为 C=26 的数组 countss 的所有字符进行词频统计,随后根据 order 的优先级进行构造
若字符 xorder 中排于 y 前面,则先往答案追加 count[s] 个字符x,再往答案追加 count[y] 个字符y,并更新对应词频,最后将仅出现在s中的字符追加到答案尾部

python代码解法

class Solution:
    def customSortString(self, order: str, s: str) -> str:
        counts = [0] * 26
        ans = ''
        for i in s:   # 遍历s进行字符出现的频率统计
            counts[ord(i) - ord('a')] += 1
        # print(counts)
        for o in order:    # 遍历order字符串
            num = ord(o) - ord('a')  
            if counts[num] >= 0:
                ans += o * counts[num]  # 按照order中出现的字符的顺序,逐个乘以字符出现的频率追加到ans末尾
                counts[num] = 0    # 将对应字符出现频率置为0

        for i in range(0, len(counts)):  # 将s中的多余字符追加到ans的末尾
            if counts[i] != 0:
                ans += chr(ord('a') + i) * counts[i]
        return ans

第二题:有多少小于当前数字的数字

Leetcode1365. 有多少小于当前数字的数字:简单题 (详情点击链接见原题)

给你一个数组 nums,对于其中每个元素 nums[i],请你统计数组中比它小的所有数字的数目

python代码解法

class Solution:
    def smallerNumbersThanCurrent(self, nums: List[int]) -> List[int]:
        ans = []
        temp = nums[:]   # 准备一个副本
        hash_map = {}
        nums.sort()
        # 构造哈希表的时候从后向前遍历,这样哈希表里存放的就是相同元素最左面的数值和下标了
        for i in range(len(nums) - 1, -1, -1):
            hash_map[nums[i]] = i
        for i in temp:
            ans.append(hash_map[i])
        return ans

三、总结

本文给大家介绍了哈希表在面试中的高频考题以及哈希表和其他算法结合的考察形式,可以看到哈希表再结合其他知识点的应用中还是稍稍有点难的,比较考察大家对于数据结构的基础知识(尤其是LRU和设计哈希集合这两道题),祝大家面试顺利,面试碰到原题,找到心仪的offer,冲冲冲~

  • 24
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

code_lover_forever

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值