8.【题单】常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
1125字约4分钟
LeetcodePython
2024-12-04
零、常用枚举技巧
0.1 枚举右,维护左
提示
灵神:对于 双变量问题,例如两数之和 ai+aj=t ,可以枚举右边的 aj,转换成 单变量问题,也就是在 aj 左边查找是否有 ai=t−aj ,这可以用哈希表维护。
我把这个技巧叫做 枚举右,维护左。
提示
阿囧:本质是用空间维护遍历过的数组左边元素状态,从而达到只用遍历一次数组求解的效果
class Solution: def twoSum(self, nums: List[int], target: int) -> List[int]: dic = {} for j, num in enumerate(nums): find = target - num if find in dic: return [dic[find], j] else: dic[num] = j
时间复杂度:O(n)
空间复杂度:O(n),哈希表空间换时间
class Solution: def numIdenticalPairs(self, nums: List[int]) -> int: cnt = defaultdict(int) res = 0 for num in nums: res += cnt[num] cnt[num] += 1 return res
时间复杂度:O(n)
空间复杂度:O(n),哈希表空间换时间
class Solution: def containsNearbyDuplicate(self, nums: List[int], k: int) -> bool: dic = {} for j, num in enumerate(nums): if num in dic.keys() and j - dic[num] <= k: return True dic[num] = j return False
时间复杂度:O(n)
空间复杂度:O(n),哈希表空间换时间
class Solution: def maxProfit(self, prices: List[int]) -> int: res = 0 min_pric, max_price = prices[0], prices[0] for price in prices: if price < min_pric: min_pric = price max_price = price # 如果买入,那么只能在 price 后面卖出 if price > max_price: max_price = price res = max(res, max_price - min_pric) # 记录最大收入 return res
时间复杂度:O(n)
空间复杂度:O(1),只用到若干常量
class Solution: def maxSum(self, nums: List[int]) -> int: help = [0] * 10 # 只有 0~9 的数字类型 res = -1 for num in nums: index = int(max(str(num))) if help[index]: res = max(res, help[index] + num) if num > help[index]: help[index] = num return res
时间复杂度:O(nlogU),其中 n 为 nums 的长度,U = max(nums)
空间复杂度:O(1),只用到若干常量
Q:这个算法复杂度中的 log 的底数是10,而常见的一般是 2,所以有没有标明一下的必要呢?
A:没有必要,不同底数之间只有常系数的差别。
class Solution: def maximumSum(self, nums: List[int]) -> int: dic = defaultdict(int) res = -1 def num_sum(num): # 求数位和 if num // 10 == 0: return num else: return num % 10 + num_sum(num // 10) for num in nums: key = num_sum(num) if dic[key]: res = max(res, dic[key] + num) if num > dic[key]: dic[key] = num return res
时间复杂度:O(nlogU),其中 n 为 nums 的长度,U = max(nums)
空间复杂度:O(DlogU),其中 D = 9
class Solution: def maxOperations(self, nums: List[int], k: int) -> int: dic = defaultdict(int) res = 0 for num in nums: if dic[num]: res += 1 dic[num] -= 1 else: dic[k - num] += 1 return res
时间复杂度:O(n),其中 n 为 nums 的长度
空间复杂度:O(n)
class Solution: def minimumCardPickup(self, cards: List[int]) -> int: res = 10e5 + 1 dic = {} for j, card in enumerate(cards): if card in dic: res = min(res, j - dic[card] + 1) dic[card] = j return -1 if res == 10e5 + 1 else res
时间复杂度:O(n),其中 n 为 cards 的长度
空间复杂度:O(n)
class Solution: def numPairsDivisibleBy60(self, time: List[int]) -> int: dic = defaultdict(int) res = 0 for j, t in enumerate(time): t = t % 60 if t == 0: res += dic[0] res += dic[60 - t] dic[t] += 1 return res
时间复杂度:O(n),其中 n 为 time 的长度
空间复杂度:O(1),由于字典 dic 中最多只有 60 个键。
class Solution: def countCompleteDayPairs(self, hours: List[int]) -> int: res = 0 dic = defaultdict(int) for hour in hours: hour = hour % 24 res += dic[24 - hour] if hour == 0: res += dic[0] dic[hour] += 1 return res
时间复杂度:O(n),其中 n 为 hours 的长度
空间复杂度:O(1),由于字典 dic 中最多只有 24 个键。