专栏其他内容:
LeetCode Hot100 中 enumerate 函数的妙用(2026.2月版)
LeetCode Hot100数据结构背景知识之列表(List)Python2026新版
LeetCode Hot100数据结构背景知识之元组(Tuple)Python2026新版
LeetCode Hot100数据结构背景知识之集合(Set)Python2026新版
Python字典(Dictionary)核心特点、基础用法与常用函数
1. 字典的核心特点
字典(Dictionary)以键值对(key-value)存储数据,支持O(1)平均时间复杂度的增删改查。
-
键值对存储:字典的基本结构是「key: value」,一个key对应一个value,key是唯一标识,value可重复、可存储任意数据类型(整数、字符串、列表、字典等)。
-
key的约束:key必须是「不可变数据类型」(如整数、字符串、元组),不可用列表、字典等可变类型(会报错);且key唯一,若重复赋值,后值会覆盖前值。
-
O(1)平均时间复杂度:增、删、改、查(判断key是否存在、获取value)的平均时间复杂度均为O(1),这是字典优于列表(O(n)查找)的核心原因,也是刷题中用字典优化效率的关键。
-
有序性(Python3.7+):3.7及以上版本中,字典会保留键值对的插入顺序,遍历字典时会按插入顺序返回;3.6及以下版本无序(刷题时无需纠结版本,主流在线判题环境均为3.7+)。
-
可变性:字典是可变数据类型,可动态添加、删除、修改键值对,无需提前定义长度(适配刷题中动态计数、映射的需求)。
2. 字典的基础用法
重点掌握「初始化」「增删改查」四大操作:
-
初始化:三种常用方式,按需选择
-
空字典(最常用):
dict1 = {}或dict1 = dict(); -
带初始键值对:
dict2 = {"a":1, "b":2}(适合已知初始映射关系); -
去重初始化:
dict3 = dict.fromkeys([1,2,3], True)(key为列表元素,value统一,快速去重)。python>>> nums = [100,4,200,1,3,2,2] >>> nums # 原始数组 [100, 4, 200, 1, 3, 2, 2] >>> num_dict = dict.fromkeys(nums, 1) >>> num_dict # 去重后的字典 {100: 1, 4: 1, 200: 1, 1: 1, 3: 1, 2: 1} >>> num_dict.keys() # 字典的键视图(不是列表) dict_keys([100, 4, 200, 1, 3, 2]) >>> unique_nums = list(num_dict.keys()) >>> unique_nums # 转换为列表后的结果 [100, 4, 200, 1, 3, 2] >>> print(unique_nums) # 最终打印输出 [100, 4, 200, 1, 3, 2]
-
-
新增/修改键值对:同一语法,key存在则修改,不存在则新增
-
常规写法:
dict1["c"] = 3(新增)、dict1["a"] = 5(修改); -
批量新增:
dict1.update({"d":4, "e":5})(适合一次性添加多个键值对)。
-
-
删除键值对:三种方式,刷题中常用前两种
-
del语句:
del dict1["a"](删除指定key,key不存在报错,需提前判断); -
pop()方法:
dict1.pop("b")(删除指定key,返回对应的value,key不存在可设默认值避免报错:dict1.pop("f", 0)); -
清空字典:
dict1.clear()(适合重复利用字典时清空数据)。
-
-
查找操作:
-
判断key是否存在(最常用):
if "a" in dict1:(O(1)时间,比列表in操作高效); -
获取value:
dict1["a"](key不存在报错)、dict1.get("a", 0)(key不存在返回默认值0)。 -
get()的作用是安全地获取字典中指定键的值 ,避免直接通过
dict[key]访问不存在的键时抛出KeyError异常。dict.get(key, default=None)python# 示例字典 score = {"Alice": 90, "Bob": 85} # 1. 直接访问不存在的键 → 报错 KeyError # print(score["Charlie"]) # 运行报错 # 2. 使用get()访问不存在的键 → 返回默认值 print(score.get("Charlie")) # 输出 None(默认值) print(score.get("Charlie", 0)) # 输出 0(自定义默认值) print(score.get("Alice", 0)) # 输出 90(键存在,返回对应值)
-
-
遍历操作:
-
遍历key(最常用):写法1(直接遍历):
for key in dict1:写法2(用keys()方法):for key in dict1.keys():遍历value:用values()方法,适合仅需获取计数结果、判断value是否符合条件的场景 写法:for val in dict1.values(): -
遍历key和val(常用):用items()方法,同时获取键值对,适配需联动key和value的场景 写法:
for key, val in dict1.items():
-
3. 字典常用函数
| 函数/方法 | 用法示例 | 功能说明 |
|---|---|---|
| get() | dict.get(key, default=0) | 获取key对应的value,不存在则返回default |
| fromkeys() | dict.fromkeys(iterable, value) | 用可迭代对象生成字典,key为迭代元素,value统一 |
| update() | dict.update(other_dict) | 批量添加/修改键值对,other_dict为字典 |
| pop() | dict.pop(key, default) | 删除key,返回value,不存在则返回default |
| keys() | dict.keys() | 返回字典中所有key的可迭代对象 |
| values() | dict.values() | 返回字典中所有value的可迭代对象 |
| items() | dict.items() | 返回字典中所有(key, value)元组的可迭代对象 |
一、LeetCode中字典的核心优势与适用场景
在算法题中,字典的核心价值是「快速建立映射关系」,替代列表的O(n)查找,从而优化整体时间复杂度。
-
计数统计:统计数组/字符串中元素出现的次数(如字符计数、数字频次),替代暴力遍历计数(时间复杂度从O(n²)降至O(n));
-
键值映射:存储「目标值-索引」「元素-对应满足条件的元素」等关系(如两数之和、两数之和II),快速定位所需元素;
-
去重与筛选:利用字典的key唯一特性,实现高效去重,或筛选符合条件的元素组合(如最长连续序列)。
二、Hot100真题实战
真题1:两数之和(Easy,Hot100 Top5)------ 键值映射的基础应用
题干:
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
字典解法思路(最优解)
核心需求:快速找到「target - 当前元素」是否在数组中,且获取其下标。
用字典存储「元素值 → 元素下标」,遍历数组时,对每个元素nums[i]:
-
计算互补值 complement = target - nums[i];
-
判断complement是否在字典的key中:若在,直接返回[字典[complement], i];
-
若不在,将当前元素nums[i]及其下标i存入字典(避免重复使用同一元素);
-
遍历结束后,必能找到答案(题干保证有解)。
字典代码实现(Python)
python
class Solution(object):
def twoSum(self, nums, target):
# 初始化空字典,存储键:元素值,值:元素下标
num_map = {}
for i in range(len(nums)):
complement = target - nums[i]
# 关键:判断互补值是否已在字典中(O(1)查找)
if complement in num_map:
return [num_map[complement], i]
# 注意:先判断再存入,避免同一元素被重复使用
num_map[nums[i]] = i
# 题干保证有解,此处可省略return
非字典代码实现:
python
class Solution(object):
def twoSum(self, nums, target):
n=len(nums)
for i in range(n):
for j in range(i+1,n):
if target == nums[i]+nums[j]:
return[i,j]
避坑点
-
不能先存入字典再判断:若先存,当nums[i] = target/2时(如target=6,nums[i]=3),会误判自己与自己求和,导致错误;
-
字典的key是元素值,不是下标:避免搞反键值对,否则无法通过互补值快速获取下标。
复杂度分析:时间O(n)(仅遍历一次数组),空间O(n)(最坏情况存储所有元素),是本题的最优解。
真题2:多数元素(Easy,Hot100 Top20)------ 计数统计的基础应用
题干:
给定一个大小为 n的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:nums = [3,2,3]
输出:3
示例 2:
输入:nums = [2,2,1,1,1,2,2]
输出:2
字典解法思路
核心需求:统计每个元素的出现次数,找到次数大于n/2的元素。
用字典存储「元素 → 出现次数」,遍历数组时完成计数,之后遍历字典,返回次数最大(且满足条件)的元素。
优化点:遍历数组时,可实时判断当前元素的次数是否已超过n/2,若超过直接返回,无需遍历完整个数组和字典。
代码实现(Python)
python
class Solution(object):
def majorityElement(self, nums):
count_map = {}
n = len(nums)
half = n // 2
for num in nums:
# 简洁写法:若num在字典中,次数+1;否则设为1
count_map[num] = count_map.get(num, 0) + 1
# 优化:实时判断,提前返回
if count_map[num] > half:
return num
# 题干保证有解,此处可省略return
哈希表实现:
python
class Solution:
def majorityElement(self, nums: List[int]) -> int:
counts = collections.Counter(nums)
return max(counts.keys(), key=counts.get)
排序实现:
python
class Solution:
def majorityElement(self, nums: List[int]) -> int:
nums.sort()
return nums[len(nums) // 2]
避坑点
-
使用get()方法简化计数逻辑:避免先判断num是否在字典中,再手动赋值,代码更简洁;
-
无需遍历完字典:多数元素的次数一定超过n/2,遍历数组时一旦满足条件,直接返回,提升效率(最坏情况仍遍历一次数组)。
真题3:最长连续序列(Medium,Hot100 Top30)------ (去重+映射)
题干:
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。请你设计并实现时间复杂度为 O(n)的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
字典解法思路(O(n)最优解)
核心难点:未排序数组,要求O(n)时间,无法用排序(排序时间O(nlogn)),需用字典快速定位连续序列的边界。
思路拆解:
-
去重:将数组元素存入字典(key为元素,value可设为布尔值或长度,此处用布尔值标记元素是否已处理,避免重复计算);
-
遍历字典的每个key(即数组中的每个唯一元素):
-
判断当前元素是否是连续序列的「起点」:即当前元素-1不在字典中(说明没有比它小1的元素,它是序列的第一个元素);
-
若为起点,开始向后计数:依次判断当前元素+1、+2...是否在字典中,统计序列长度;
-
更新最长序列长度,遍历结束后返回最大值。
-
关键:每个元素仅被处理一次(处理起点时,会一次性遍历整个连续序列,后续遍历到序列中的其他元素时,因不是起点,直接跳过),保证时间复杂度O(n)。
字典代码实现(Python)
python
class Solution(object):
def longestConsecutive(self, nums):
"""
利用哈希表(字典)求解最长连续序列
:type nums: List[int]
:rtype: int
"""
# 1. 去重:将数字存入字典,键为数字,值为该数字所在连续序列的长度
# 去重是为了避免重复处理相同数字,比如 nums = [1,2,0,1] 中的 1 只处理一次
num_dict = {}
max_length = 0 # 记录最长连续序列的长度
for num in nums:
# 2. 只处理未在字典中的数字(去重)
if num not in num_dict:
# 3. 获取当前数字左右相邻数字的连续序列长度
# left_len:num-1 所在连续序列的长度(如果不存在则为0)
left_len = num_dict.get(num - 1, 0)
# right_len:num+1 所在连续序列的长度(如果不存在则为0)
right_len = num_dict.get(num + 1, 0)
# 4. 当前数字所在连续序列的总长度 = 左长度 + 右长度 + 1(自身)
current_len = left_len + right_len + 1
# 5. 更新最长长度
if current_len > max_length:
max_length = current_len
# 6. 更新字典:只需更新连续序列的「边界」值即可
# 因为后续只会查询边界数字的长度,中间数字不会再被用到
num_dict[num] = current_len # 更新当前数字的长度
num_dict[num - left_len] = current_len # 更新左边界的长度
num_dict[num + right_len] = current_len # 更新右边界的长度
return max_length
集合代码实现(Python)
python
from typing import List
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
longest_streak = 0 # 记录最长连续序列长度
num_set = set(nums) # 转集合:去重 + O(1)时间查找
# 遍历去重后的每个数字
for num in num_set:
# 关键:只有当num是连续序列的「起点」(num-1不存在)时,才开始统计
if num - 1 not in num_set:
current_num = num # 当前遍历的数字
current_streak = 1 # 当前连续序列长度
# 向后查找连续数字(current_num+1是否存在)
while current_num + 1 in num_set:
current_num += 1
current_streak += 1
# 更新最长长度
longest_streak = max(longest_streak, current_streak)
return longest_streak
避坑点
-
去重是关键:数组中可能有重复元素(如示例2中的0),用字典去重后,避免重复处理同一元素,降低时间复杂度;
-
仅处理起点:若不判断num-1是否在字典中,会对每个元素都向后计数,导致时间复杂度升至O(n²)(如序列[1,2,3,4],会对1、2、3、4分别计数);
-
边界条件:空数组返回0,避免遍历字典时出错。