-
设计哈希表
-
705. 设计哈希集合
class MyHashSet: def __init__(self): self.keyRange = 769 self.bucketArray = [Bucket() for i in range(self.keyRange)] def _hash(self, key): return key % self.keyRange def add(self, key): bucketIndex = self._hash(key) self.bucketArray[bucketIndex].insert(key) def remove(self, key): bucketIndex = self._hash(key) self.bucketArray[bucketIndex].delete(key) def contains(self, key): bucketIndex = self._hash(key) return self.bucketArray[bucketIndex].exists(key) class Bucket: def __init__(self): self.tree = BSTree() def insert(self, val): self.tree.root = self.tree.insertIntoBST(self.tree.root, val) def delete(self, val): self.tree.root = self.tree.deleteNode(self.tree.root, val) def exists(self, val): return bool(self.tree.searchBST(self.tree.root, val)) class TreeNode: def __init__(self, value, left=None, right=None): self.val = value self.left = left self.right = right class BSTree: def __init__(self): self.root = None def searchBST(self, root, val): if root is None or val == root.val: return root return self.searchBST(root.left, val) if val < root.val else self.searchBST(root.right, val) def insertIntoBST(self, root, val): if not root: return TreeNode(val) if val > root.val: root.right = self.insertIntoBST(root.right, val) elif val == root.val: return root else: root.left = self.insertIntoBST(root.left, val) return root def successor(self, root): root = root.right while root.left: root = root.left return root.val def predecessor(self, root): root = root.left while root.right: root = root.right return root.val def deleteNode(self, root, key): if not root: return None if key > root.val: root.right = self.deleteNode(root.right, key) elif key < root.val: root.left = self.deleteNode(root.left, key) else: if not (root.left or root.right): root = None elif root.right: root.val = self.successor(root) root.right = self.deleteNode(root.right, root.val) else: root.val = self.predecessor(root) root.left = self.deleteNode(root.left, root.val) return root # Your MyHashSet object will be instantiated and called as such: # obj = MyHashSet() # obj.add(key) # obj.remove(key) # param_3 = obj.contains(key) -
706. 设计哈希映射
class Bucket: def __init__(self): self.bucket = [] def get(self, key): for k, v in self.bucket: if k == key: return v return -1 def update(self, key, val): found = False for i, (k, v) in enumerate(self.bucket): if key == k: self.bucket[i] = (key, val) found = True break if not found: self.bucket.append((key, val)) def remove(self, key): for i, (k, v) in enumerate(self.bucket): if key == k: del self.bucket[i] class MyHashMap: def __init__(self): self.key_space = 769 self.hash_table = [Bucket() for _ in range(self.key_space)] def put(self, key, val): idx = key % self.key_space self.hash_table[idx].update(key, val) def get(self, key): idx = key % self.key_space return self.hash_table[idx].get(key) def remove(self, key): idx = key % self.key_space self.hash_table[idx].remove(key) # Your MyHashMap object will be instantiated and called as such: # obj = MyHashMap() # obj.put(key,value) # param_2 = obj.get(key) # obj.remove(key)
-
-
哈希表与滑动窗口
-
219. 存在重复元素 II
class Solution: def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool: window = Counter() left = 0 for right, ch in enumerate(nums): window[ch] += 1 while left <= right and right-left+1 > k+1: window[nums[left]] -= 1 left += 1 if window[ch] > 1: return True return False -
424. 替换后的最长重复字符
class Solution: def characterReplacement(self, s: str, k: int) -> int: window = Counter() ans = maxn = left = 0 for right, ch in enumerate(s): window[ch] += 1 maxn = max(maxn, window[ch]) # 滑动窗口大小 - 窗口里出现次数最多的字母次数 = 其他字母的总个数 while left <= right and right-left+1 - maxn > k: window[s[left]] -= 1 left += 1 ans = max(ans, right-left+1) return ans -
1004. 最大连续1的个数 III
class Solution: def longestOnes(self, nums: List[int], k: int) -> int: window = Counter() ans = maxn = left = 0 for right, num in enumerate(nums): window[num] += 1 maxn = max(maxn, window[1]) while left <= right and right-left+1 - maxn > k: window[nums[left]] -= 1 left += 1 ans = max(ans, right-left+1) return ans -
3. 无重复字符的最长子串
class Solution: def lengthOfLongestSubstring(self, s: str) -> int: window = Counter() ans = left = 0 for right, ch in enumerate(s): window[ch] += 1 while left <= right and right-left+1 != len(window): window[s[left]] -= 1 if window[s[left]] == 0: del window[s[left]] left += 1 ans = max(ans, right-left+1) return ans -
159. 至多包含两个不同字符的最长子串
class Solution: def lengthOfLongestSubstringTwoDistinct(self, s: str) -> int: window = Counter() ans = left = 0 for right, ch in enumerate(s): window[ch] += 1 while left <= right and len(window) > 2: window[s[left]] -= 1 if window[s[left]] == 0: del window[s[left]] left += 1 ans = max(ans, right-left+1) return ans
-
-
实际应用 - 设计键
-
49. 字母异位词分组
class Solution: def groupAnagrams(self, strs: List[str]) -> List[List[str]]: # 字符串中对应字符个数一致的时候 def hashKey(s: str) -> Tuple[int]: count = [0] * 26 for ch in s: count[ord(ch) - ord('a')] += 1 return tuple(count) ans = defaultdict(list) for s in strs: ans[hashKey(s)].append(s) return list(ans.values()) -
249. 移位字符串分组
class Solution: def groupStrings(self, strings: List[str]) -> List[List[str]]: # 字符串之间可以移位得到必然是每一位距离差对应一致的时候 def hashKey(s: str) -> Tuple[int]: n = len(s) if n <= 1: return 0 diff = [] for i in range(1, n): diff.append((ord(s[i]) - ord(s[i-1])) % 26) return tuple(diff) ans = defaultdict(list) for s in strings: ans[hashKey(s)].append(s) return list(ans.values()) -
36. 有效的数独
class Solution: def isValidSudoku(self, board: List[List[str]]) -> bool: # 在矩阵中,你可能会使用 行索引 或 列索引 作为键 # 如果需要将矩阵分块,可以将行索引和列索引进行组合以标识该元素属于哪个块 # 有时,在矩阵中,你可能会希望将对角线的元素组合在一起,比如八皇后问题 row = [[0] * 10 for _ in range(9)] col = [[0] * 10 for _ in range(9)] block = [[0] * 10 for _ in range(9)] for i in range(9): for j in range(9): if board[i][j] != '.': num = int(board[i][j]) blockIdx = (i // 3) * 3 + j // 3 if row[i][num] or col[j][num] or block[blockIdx][num]: return False row[i][num] = col[j][num] = block[blockIdx][num] = 1 return True -
652. 寻找重复的子树
# Definition for a binary tree node. # class TreeNode: # def __init__(self, val=0, left=None, right=None): # self.val = val # self.left = left # self.right = right class Solution: def findDuplicateSubtrees(self, root: Optional[TreeNode]) -> List[Optional[TreeNode]]: ans = defaultdict(list) def dfs(node: Optional[TreeNode]) -> str: if not node: return '#' # serial = '{},{},{}'.format(dfs(node.left), dfs(node.right), node.val) 也可以, # 但是不能node.val写中间,因为写中间无法区分等高的斜子树(比如说两棵树等高为2,但是一个左斜,一个右斜) leftRet = dfs(node.left) rightRet = dfs(node.right) def hashKey(): return '{},{},{}'.format(node.val, leftRet, rightRet) serial = hashKey() ans[serial].append(node) return serial dfs(root) return [ans[k][0] for k in ans.keys() if len(ans[k]) >= 2] -
311. 稀疏矩阵的乘法
class Solution: def multiply(self, mat1: List[List[int]], mat2: List[List[int]]) -> List[List[int]]: r1, c1 = len(mat1), len(mat1[0]) r2, c2 = len(mat2), len(mat2[0]) m1 = defaultdict(Counter) for r in range(r1): for c in range(c1): if mat1[r][c] != 0: m1[r][c] = mat1[r][c] m2 = defaultdict(Counter) for c in range(c2): for r in range(r2): if mat2[r][c] != 0: m2[c][r] = mat2[r][c] ans = [[0] * c2 for _ in range(r1)] for k1, v1 in m1.items(): for k2, v2 in m2.items(): ans[k1][k2] = sum([v * v2[k] for k, v in v1.items()]) return ans
-
-
小结与讨论
-
454. 四数相加 II
class Solution: def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int: countAB = Counter([u + v for u in nums1 for v in nums2]) ans = 0 for u in nums3: for v in nums4: if -u - v in countAB: ans += countAB[-u - v] return ans -
380. O(1) 时间插入、删除和获取随机元素
class RandomizedSet: def __init__(self): self.d = {} self.l = [] def insert(self, val: int) -> bool: if val in self.d: return False self.d[val] = len(self.l) self.l.append(val) return True # 需要删除时可以交换val和list[-1],然后删除pop就是O(1)的 def remove(self, val: int) -> bool: if val in self.d: last_elem = self.l[-1] idx = self.d[val] self.d[last_elem] = idx self.l[idx] = last_elem self.l.pop() del self.d[val] return True return False def getRandom(self) -> int: return random.choice(self.l)
-