python中的dict()

在 Python 中,dict() 是创建字典的内置函数,字典是一种键值对(key-value pair)的数据结构。由于字典具有高效的键值查找、插入和删除操作,在 LeetCode 刷题中非常常用,尤其是处理映射关系、快速查找、计数、前缀匹配等问题时。


基本特性

  1. 键值对存储:字典中的每个元素是一个键值对,形式为 key: value
  2. 键的唯一性:字典的键必须唯一,重复键会覆盖之前的值。
  3. 可变性:字典支持动态添加、修改和删除键值对。
  4. 键必须可哈希:键可以是字符串、数字或元组等不可变类型,不能是列表或字典。

常见用法和语法

1. 创建字典

  • 空字典
    d = {}
    print(d)  # 输出: {}
    
  • 通过 dict() 创建
    d = dict(a=1, b=2)
    print(d)  # 输出: {'a': 1, 'b': 2}
    
  • 通过键值对创建
    d = {'key1': 'value1', 'key2': 'value2'}
    print(d)  # 输出: {'key1': 'value1', 'key2': 'value2'}
    

2. 访问和修改字典

  • 访问值

    d = {'a': 1, 'b': 2}
    print(d['a'])  # 输出: 1
    

    如果键不存在,直接访问会报错。

  • 使用 get() 方法

    print(d.get('c', 'default'))  # 输出: 'default'
    

    如果键不存在,返回默认值 default

  • 添加或修改键值对

    d['c'] = 3
    print(d)  # 输出: {'a': 1, 'b': 2, 'c': 3}
    

3. 删除元素

  • 使用 del
    del d['a']
    print(d)  # 输出: {'b': 2, 'c': 3}
    
  • 使用 pop()
    value = d.pop('b', 'default')
    print(value)  # 输出: 2
    print(d)  # 输出: {'c': 3}
    

4. 遍历字典

  • 遍历键
    for key in d:
        print(key)
    
  • 遍历值
    for value in d.values():
        print(value)
    
  • 遍历键值对
    for key, value in d.items():
        print(key, value)
    

5. 字典推导式

  • 快速创建字典
    squares = {x: x**2 for x in range(5)}
    print(squares)  # 输出: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
    

在算法题中,字典(dict)是最常用的数据结构之一,主要用于高效查找、计数和映射。以下是针对算法竞赛的字典核心方法与应用场景总结:


一、高频方法速查表

方法 时间复杂度 典型应用场景 示例
dict.get(key, default) O(1) 安全访问(防KeyError) counts.get(x, 0)
dict.setdefault(key, default) O(1) 初始化复合值 dict.setdefault(k, []).append(v)
dict.keys() O(1)* 遍历键 for k in d:(直接迭代)
dict.values() O(1)* 遍历值 sum(d.values())
dict.items() O(1)* 遍历键值对 for k, v in d.items()
key in dict O(1) 成员检查 if k in d:
dict.pop(key, default) O(1) 删除并返回值 d.pop('old', None)
dict.update(other_dict) O(len(other)) 合并字典 d1.update(d2)
collections.defaultdict - 自动初始化缺失键 dd = defaultdict(int)
collections.Counter - 频率统计 Counter(arr).most_common(2)

注:keys()/values()/items()在Python 3中返回视图对象,实际迭代O(n)


二、算法题核心应用场景

1. 频率统计(Top K元素)

from collections import Counter

arr = [1, 2, 2, 3, 3, 3]
cnt = Counter(arr)

# 获取最高频的2个元素
print(cnt.most_common(2))  # [(3, 3), (2, 2)]

# 手动实现
freq = {}
for x in arr:
    freq[x] = freq.get(x, 0) + 1
top_k = sorted(freq.items(), key=lambda x: x[1], reverse=True)[:2]

2. 索引映射(两数之和)

def two_sum(nums, target):
    seen = {}  # 值->索引映射
    for i, n in enumerate(nums):
        complement = target - n
        if complement in seen:
            return [seen[complement], i]
        seen[n] = i
    return []

3. 分组归类(相同字母异位词)

words = ["eat", "tea", "tan", "ate", "nat", "bat"]
groups = {}
for w in words:
    key = ''.join(sorted(w))  # 排序后的字符串作为键
    groups.setdefault(key, []).append(w)
print(list(groups.values()))  # [['eat','tea','ate'], ['tan','nat'], ['bat']]

4. 状态缓存(动态规划/记忆化搜索)

memo = {}
def fib(n):
    if n <= 1: return n
    if n not in memo:
        memo[n] = fib(n-1) + fib(n-2)
    return memo[n]

5. 最近访问记录(LRU缓存)

from collections import OrderedDict
class LRUCache:
    def __init__(self, capacity):
        self.cache = OrderedDict()
        self.cap = capacity

    def get(self, key):
        if key not in self.cache: return -1
        self.cache.move_to_end(key)  # 标记为最近使用
        return self.cache[key]

    def put(self, key, value):
        if key in self.cache:
            self.cache.move_to_end(key)
        self.cache[key] = value
        if len(self.cache) > self.cap:
            self.cache.popitem(last=False)  # 移除最旧项

三、进阶技巧

1. 复合键(元组作为键)

# 坐标统计
points = [(1,2), (3,4), (1,2)]
coord_count = {}
for p in points:
    coord_count[p] = coord_count.get(p, 0) + 1
print(coord_count)  # {(1,2): 2, (3,4): 1}

2. 字典模拟图结构

graph = {
    'A': ['B', 'C'],
    'B': ['D'],
    'C': ['E'],
    'D': [],
    'E': ['B']
}

# BFS遍历
from collections import deque
def bfs(start):
    visited = set()
    queue = deque([start])
    while queue:
        node = queue.popleft()
        if node in visited: 
            continue
        visited.add(node)
        for neighbor in graph.get(node, []):
            queue.append(neighbor)

3. 双向映射(双字典)

# 维护一一对应关系
forward_map = {}
reverse_map = {}
def add_pair(a, b):
    if a in forward_map or b in reverse_map:
        return False
    forward_map[a] = b
    reverse_map[b] = a
    return True

def remove_by_a(a):
    if a not in forward_map: return
    b = forward_map[a]
    del forward_map[a]
    del reverse_map[b]

四、性能注意事项

  1. 避免频繁创建字典:在循环外初始化字典
  2. 优先用in检查:而非try-except KeyError(除非异常概率>25%)
  3. 视图对象高效操作
    d = {'a':1, 'b':2}
    keys_view = d.keys()
    # 支持集合操作
    print(keys_view & {'a', 'c'})  # {'a'}
    
  4. 字典推导式
    # 快速创建字典
    square_dict = {x: x*x for x in range(5)}  # {0:0, 1:1, 2:4, ...}
    

五、常见坑点

  1. 可变对象作为键
    # 列表不可哈希,需转元组
    valid_dict = {tuple([1,2]): "value"}  # 正确
    # invalid_dict = {[1,2]: "value"}    # TypeError
    
  2. 字典顺序依赖
    # Python 3.6以下版本无顺序保证
    # 需有序时显式使用OrderedDict
    
  3. 默认值陷阱
    # 使用defaultdict时避免共享引用
    dd = defaultdict(list)   # 安全:每次创建新列表
    # dd = defaultdict(lambda: [])  # 等效写法
    

LeetCode 中常用场景

1. 统计频率

统计字符或数字的出现次数:

nums = [1, 2, 2, 3, 3, 3]
count = {}
for num in nums:
    count[num] = count.get(num, 0) + 1
print(count)  # 输出: {1: 1, 2: 2, 3: 3}

2. 检查映射关系

判断两个字符串是否存在一一映射:

def isIsomorphic(s, t):
    mapping_s_t = {}
    mapping_t_s = {}
    for c1, c2 in zip(s, t):
        if c1 in mapping_s_t and mapping_s_t[c1] != c2:
            return False
        if c2 in mapping_t_s and mapping_t_s[c2] != c1:
            return False
        mapping_s_t[c1] = c2
        mapping_t_s[c2] = c1
    return True

3. 前缀匹配

用于实现 Trie(字典树)相关题目:

class Trie:
    def __init__(self):
        self.children = {}
        self.is_end = False

    def insert(self, word):
        node = self
        for char in word:
            if char not in node.children:
                node.children[char] = Trie()
            node = node.children[char]
        node.is_end = True

4. 两数之和

使用字典快速查找补数:

def twoSum(nums, target):
    d = {}
    for i, num in enumerate(nums):
        if target - num in d:
            return [d[target - num], i]
        d[num] = i

5. 滑动窗口问题

用字典记录窗口内字符频率:

def lengthOfLongestSubstring(s):
    char_index = {}
    start = max_len = 0
    for i, char in enumerate(s):
        if char in char_index and char_index[char] >= start:
            start = char_index[char] + 1
        char_index[char] = i
        max_len = max(max_len, i - start + 1)
    return max_len

效率优势

  1. 查找:字典的查找操作时间复杂度为 ( O(1) )。
  2. 插入和删除:字典的插入和删除操作也为 ( O(1) ),适合大规模数据的快速操作。
  3. 遍历:遍历时间复杂度为 ( O(n) ),取决于字典中元素的数量。

在 LeetCode 中,利用字典可以显著优化性能,尤其在需要频繁查找、统计或建立映射关系的题目中。

posted @ 2024-12-31 10:54  清澈的澈  阅读(123)  评论(0)    收藏  举报