Python 中 enumerate 函數(shù)的巧妙用法
在算法題目中,處理數(shù)組(List)、字符串、矩陣等可迭代對(duì)象時(shí),“同時(shí)獲取索引和元素值” 是高頻需求 —— 比如找目標(biāo)元素的位置、雙指針遍歷標(biāo)記、矩陣行列定位等。Python 內(nèi)置的 enumerate 函數(shù)正是用來解決這類問題的。
一、enumerate 函數(shù)的核心基礎(chǔ)
1. 什么是 enumerate?
enumerate 直譯是 “枚舉”,是 Python 內(nèi)置函數(shù),核心作用是遍歷可迭代對(duì)象時(shí),同時(shí)返回元素的 “索引” 和 “值”。它底層由 C 實(shí)現(xiàn),執(zhí)行效率略高于手動(dòng)維護(hù)索引的寫法,是刷題時(shí)的首選。
2. 基礎(chǔ)語法
enumerate(iterable, start=0)
- 參數(shù):
iterable:必需,可迭代對(duì)象(List、字符串、元組、矩陣等);start:可選,索引起始值,默認(rèn) 0(可根據(jù)題目需求設(shè)為 1、-1 等)。
- 返回值:枚舉對(duì)象(迭代器),每次迭代返回
(索引, 元素值)元組。
3. 告別手動(dòng)索引
# 傳統(tǒng)寫法
nums = [1, 3, 5, 7]
i = 0
for val in nums:
print(f"索引 {i}:值 {val}")
i += 1
# enumerate 寫法
for idx, val in enumerate(nums):
print(f"索引 {idx}:值 {val}")
# 自定義索引起始值(比如題目要求索引從 1 開始)
for idx, val in enumerate(nums, start=1):
print(f"索引 {idx}:值 {val}")二、LeetCode Hot100 中的高頻應(yīng)用場(chǎng)景
一、題目 1:兩數(shù)之和(LeetCode 1,Hot100 長期在榜)
題目原文:
給定一個(gè)整數(shù)數(shù)組 nums 和一個(gè)整數(shù)目標(biāo)值 target,請(qǐng)你在該數(shù)組中找出和為目標(biāo)值 target 的那兩個(gè)整數(shù),并返回它們的數(shù)組下標(biāo)。假設(shè)每種輸入只會(huì)對(duì)應(yīng)一個(gè)答案,數(shù)組中同一個(gè)元素在答案里不能重復(fù)出現(xiàn),可按任意順序返回答案。
傳統(tǒng)暴力解法:
class Solution(object):
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
n=len(nums)
for i in range(n):
for j in range(i+1,n):
if target == nums[i]+nums[j]:
return[i,j]傳統(tǒng)暴力解法需要兩層循環(huán)(時(shí)間復(fù)雜度 O(n2)),而哈希表可以將「查找另一個(gè)數(shù)」的操作從 O(n) 降到 O(1),整體時(shí)間復(fù)雜度優(yōu)化為 O(n),空間復(fù)雜度 O(n)(存儲(chǔ)哈希表):
from typing import List # 導(dǎo)入List類型注解,用于指定參數(shù)和返回值類型
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
"""
給定一個(gè)整數(shù)數(shù)組 nums 和一個(gè)整數(shù)目標(biāo)值 target,
請(qǐng)你在該數(shù)組中找出 和為目標(biāo)值 target 的那 兩個(gè) 整數(shù),并返回它們的數(shù)組下標(biāo)。
你可以假設(shè)每種輸入只會(huì)對(duì)應(yīng)一個(gè)答案,且同一個(gè)元素不能使用兩遍。
你可以按任意順序返回答案。
:param nums: 整數(shù)數(shù)組,存儲(chǔ)待查找的數(shù)字
:param target: 目標(biāo)和,需要找到兩個(gè)數(shù)相加等于該值
:return: 包含兩個(gè)數(shù)下標(biāo)List[int],順序無要求
"""
# 初始化一個(gè)空字典(哈希表),用于存儲(chǔ)「數(shù)字: 下標(biāo)」的映射
# 作用:將遍歷過的數(shù)字和其下標(biāo)記錄下來,后續(xù)可以O(shè)(1)時(shí)間查詢是否存在目標(biāo)差值
hashtable = dict()
# 遍歷數(shù)組,enumerate同時(shí)返回下標(biāo)i和對(duì)應(yīng)數(shù)字num
for i, num in enumerate(nums):
# 計(jì)算目標(biāo)差值:target - 當(dāng)前數(shù)字 = 需要找的另一個(gè)數(shù)
complement = target - num
# 檢查哈希表中是否已經(jīng)存在這個(gè)差值
# 如果存在,說明之前遍歷過的某個(gè)數(shù)字和當(dāng)前數(shù)字相加等于target
if complement in hashtable:
# 返回「差值對(duì)應(yīng)的下標(biāo)」和「當(dāng)前數(shù)字的下標(biāo)」,即為答案
return [hashtable[complement], i]
# 如果不存在,將當(dāng)前數(shù)字和其下標(biāo)存入哈希表,供后續(xù)遍歷查詢
# 注意:先檢查再存入,避免同一個(gè)元素被重復(fù)使用(比如num=3, target=6時(shí),不會(huì)匹配到自己)
hashtable[nums[i]] = i
# 題目保證有且僅有一個(gè)答案,理論上不會(huì)執(zhí)行到這里,返回空列表作為兜底
return []核心場(chǎng)景:需要 “值 + 下標(biāo)” 綁定且下標(biāo)是答案的一部分
enumerate的核心作用:遍歷數(shù)組時(shí),既要獲取元素值(計(jì)算補(bǔ)數(shù)target-num),又要記錄該值對(duì)應(yīng)的下標(biāo)(最終需要返回下標(biāo)作為答案)。
適用細(xì)節(jié):
- 題目要求返回 “滿足條件的元素下標(biāo)”,而非元素值,因此必須把 “值” 和 “其原始下標(biāo)” 綁定;
enumerate省去了 “手動(dòng)維護(hù)下標(biāo)變量i+i+=1” 的操作,且讓 “值 - 下標(biāo)” 的映射在循環(huán)中直接可用,避免先存所有 “值 - 下標(biāo)” 再二次遍歷的冗余。
二、題目 2:移動(dòng)零(LeetCode 283,Hot100 高頻數(shù)組題)
題目原文:
給定一個(gè)數(shù)組 nums,編寫一個(gè)函數(shù)將所有 0 移動(dòng)到數(shù)組的末尾,同時(shí)保持非零元素的相對(duì)順序。要求原地操作,不拷貝額外數(shù)組,盡量減少操作次數(shù)。
非enumerate解法:
class Solution(object):
def moveZeroes(self, nums):
n=len(nums)
left = right = 0
while right<n:
if nums[right]!=0:
nums[left],nums[right]=nums[right],nums[left]
left+=1
right+=1enumerate解法:
class Solution(object):
def moveZeroes(self, nums):
slow = 0 # 慢指針:記錄非零元素應(yīng)存放的位置,初始為0
# enumerate的fast_idx作為快指針,遍歷數(shù)組篩選非零元素
for fast_idx, val in enumerate(nums):
if val != 0: # 遇到非零元素,與慢指針位置交換并后移慢指針
nums[slow], nums[fast_idx] = nums[fast_idx], nums[slow]
slow += 1核心場(chǎng)景:雙指針遍歷,快指針需同時(shí)獲取 “索引 + 值” 做篩選
enumerate的核心作用:快指針遍歷數(shù)組時(shí),既要通過val判斷 “是否為 0”(篩選非零元素),又要通過fast_idx(enumerate 的索引)與慢指針交換元素(原地修改數(shù)組)。
適用細(xì)節(jié):
- 題目要求 “原地修改數(shù)組”,需要通過索引定位元素位置進(jìn)行交換;
enumerate讓快指針的 “索引(交換位置)” 和 “值(篩選條件)” 在同一循環(huán)變量中,無需單獨(dú)通過nums[i]取值,邏輯更緊湊。
三、題目 3:找到字符串中所有字母異位詞(LeetCode 438,Hot100 滑動(dòng)窗口題)
題目原文
給定兩個(gè)字符串 s 和 p,找到 s 中所有 p 的 字母異位詞 的子串,返回這些子串的起始索引。字母異位詞指由相同字母重排列形成的字符串(包括相同字符串),不考慮答案輸出的順序。
非enumerate寫法:
class Solution(object):
def findAnagrams(self, s, p):
"""
:type s: str # 原字符串
:type p: str # 目標(biāo)異位詞的基準(zhǔn)字符串
:rtype: List[int] # 返回所有異位詞在s中的起始索引
"""
# 初始化結(jié)果列表
result = []
# 獲取p和s的長度
len_p, len_s = len(p), len(s)
# 邊界條件:如果p比s長,不可能有異位詞,直接返回空列表
if len_p > len_s:
return result
# 初始化兩個(gè)數(shù)組,統(tǒng)計(jì)26個(gè)小寫字母的出現(xiàn)次數(shù)(ASCII碼映射)
# ord('a') = 97,所以用 ord(c) - ord('a') 得到0-25的索引
count_p = [0] * 26
count_window = [0] * 26
# 第一步:統(tǒng)計(jì)p的字符計(jì)數(shù),同時(shí)初始化滑動(dòng)窗口的初始狀態(tài)(前l(fā)en_p個(gè)字符)
for i in range(len_p):
# 統(tǒng)計(jì)p的字符
count_p[ord(p[i]) - ord('a')] += 1
# 統(tǒng)計(jì)s前l(fā)en_p個(gè)字符(初始窗口)
count_window[ord(s[i]) - ord('a')] += 1
# 檢查初始窗口是否匹配
if count_p == count_window:
result.append(0)
# 第二步:滑動(dòng)窗口遍歷s的剩余部分(從len_p到len_s-1)
# 窗口起始索引從1開始,結(jié)束索引從len_p開始
for right in range(len_p, len_s):
# 移出窗口左側(cè)的字符(窗口起始索引是 right - len_p)
left_char = s[right - len_p]
count_window[ord(left_char) - ord('a')] -= 1
# 移入窗口右側(cè)的新字符
right_char = s[right]
count_window[ord(right_char) - ord('a')] += 1
# 檢查當(dāng)前窗口是否匹配p的字符計(jì)數(shù)
if count_p == count_window:
# 記錄當(dāng)前窗口的起始索引
result.append(right - len_p + 1)
return resultenumerate寫法:
class Solution(object):
def findAnagrams(self, s, p):
"""
:type s: str
:type p: str
:rtype: List[int]
"""
result = []
len_p, len_s = len(p), len(s)
# 邊界條件:p比s長直接返回空
if len_p > len_s:
return result
# 初始化26字母計(jì)數(shù)數(shù)組
count_p = [0] * 26
count_window = [0] * 26
# 第一步:統(tǒng)計(jì)p的字符,同時(shí)初始化窗口前l(fā)en_p個(gè)字符(用enumerate遍歷)
# 遍歷p的字符,統(tǒng)計(jì)計(jì)數(shù)
for idx, char in enumerate(p):
count_p[ord(char) - ord('a')] += 1
# 遍歷s前l(fā)en_p個(gè)字符,初始化窗口(用enumerate更清晰)
for idx, char in enumerate(s[:len_p]):
count_window[ord(char) - ord('a')] += 1
# 檢查初始窗口是否匹配
if count_p == count_window:
result.append(0)
# 第二步:滑動(dòng)窗口(用enumerate遍歷s中從len_p開始的部分)
# 遍歷的是s[len_p:],enumerate的start參數(shù)指定索引從len_p開始(對(duì)應(yīng)原s的索引)
for right_idx, right_char in enumerate(s[len_p:], start=len_p):
# 計(jì)算要移出窗口的左側(cè)字符的索引
left_idx = right_idx - len_p
left_char = s[left_idx]
# 移出左側(cè)字符:計(jì)數(shù)-1
count_window[ord(left_char) - ord('a')] -= 1
# 移入右側(cè)新字符:計(jì)數(shù)+1
count_window[ord(right_char) - ord('a')] += 1
# 檢查當(dāng)前窗口是否匹配,匹配則記錄起始索引(left_idx + 1)
if count_p == count_window:
result.append(left_idx + 1)
return result核心場(chǎng)景:滑動(dòng)窗口遍歷,需索引計(jì)算窗口邊界 + 值維護(hù)窗口狀態(tài)
enumerate的核心作用:遍歷字符串時(shí),既要通過char(值)更新窗口字符計(jì)數(shù),又要通過idx(索引)計(jì)算窗口左邊界(idx - p_len + 1)、判斷窗口長度是否達(dá)標(biāo)。
適用細(xì)節(jié):
- 題目要求返回 “異位詞子串的起始索引”,需要通過索引定位窗口位置;
enumerate讓 “當(dāng)前字符” 和 “當(dāng)前位置” 直接綁定,避免手動(dòng)計(jì)算索引時(shí)的錯(cuò)位(比如窗口左邊界計(jì)算錯(cuò)誤)。
四、題目4:矩陣置零(LeetCode 73)
題目原文
給定一個(gè) m x n 的矩陣,如果一個(gè)元素為 0,則將其所在行和列的所有元素都設(shè)為 0。請(qǐng)使用 原地 算法。
進(jìn)階:能否使用 O (1) 額外空間?
非enumerate解法:
class Solution(object):
def setZeroes(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: None Do not return anything, modify matrix in-place instead.
"""
# 初始化兩個(gè)集合,分別存儲(chǔ)需要置零的行和列
rows = set()
cols = set()
# 第一步:遍歷矩陣,標(biāo)記需要置零的行和列
m = len(matrix) # 矩陣的行數(shù)
if m == 0:
return
n = len(matrix[0]) # 矩陣的列數(shù)
for i in range(m):
for j in range(n):
if matrix[i][j] == 0:
rows.add(i)
cols.add(j)
# 第二步:根據(jù)標(biāo)記的行和列,將對(duì)應(yīng)位置置零
for i in range(m):
for j in range(n):
if i in rows or j in cols:
matrix[i][j] = 0enumerate解法:
class Solution(object):
def setZeroes(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: None Do not return anything, modify matrix in-place instead.
"""
# 初始化兩個(gè)集合,分別存儲(chǔ)需要置零的行和列
rows = set()
cols = set()
# 第一步:遍歷矩陣,用enumerate獲取行索引+行數(shù)據(jù),標(biāo)記需要置零的行和列
# 外層enumerate:i是行索引,row是當(dāng)前行的所有元素
for i, row in enumerate(matrix):
# 內(nèi)層enumerate:j是列索引,val是當(dāng)前位置的元素值
for j, val in enumerate(row):
if val == 0:
rows.add(i) # 標(biāo)記需要置零的行
cols.add(j) # 標(biāo)記需要置零的列
# 第二步:再次遍歷矩陣,根據(jù)標(biāo)記置零(同樣用enumerate)
for i, row in enumerate(matrix):
for j, _ in enumerate(row): # 只需要列索引j,元素值用_占位即可
if i in rows or j in cols:
matrix[i][j] = 0- 遍歷需同時(shí)用 “索引 + 值”:
- 外層
enumerate(matrix):i是行索引(用于標(biāo)記首列matrix[i][0]),row是行元素(用于內(nèi)層遍歷); - 內(nèi)層
enumerate(row):j是列索引(用于標(biāo)記首行matrix[0][j]),val是元素值(判斷是否為 0);兩者缺一不可,完全符合 “要值也要索引” 的核心場(chǎng)景。
- 外層
- 原地修改依賴索引定位:題目要求 “原地算法”,置零操作需要通過行索引
i、列索引j精準(zhǔn)定位元素位置(如matrix[i][j] = 0),enumerate省去了手動(dòng)維護(hù)i/j自增的麻煩。
三、enumerate 進(jìn)階技巧
1. 與列表推導(dǎo)式結(jié)合:一行生成 “值 - 索引” 映射
刷題中常需要快速查找元素的位置,用 enumerate + 字典推導(dǎo)式可一鍵生成映射表:
# 生成“元素值: 作為字典的“鍵”(適用于無重復(fù)元素的數(shù)組)
nums = [2, 7, 11, 15]
# 字典推導(dǎo)式 + enumerate:鍵是元素值,值是對(duì)應(yīng)索引
val2idx = {val: idx for idx, val in enumerate(nums)}
print(val2idx[7]) # 輸出:1(快速找到7的索引)適用場(chǎng)景:Hot100 兩數(shù)之和(快速通過值找索引,時(shí)間復(fù)雜度從 O (n²) 降為 O (n))。
2. 轉(zhuǎn)換為列表:查看枚舉結(jié)果(調(diào)試 / 驗(yàn)證用)
enumerate 返回的是迭代器,只能遍歷一次;若需多次使用,可轉(zhuǎn)為列表:
nums = [10, 20, 30] # 將枚舉對(duì)象轉(zhuǎn)為列表,方便查看所有(索引,值)對(duì) enum_list = list(enumerate(nums)) print(enum_list) # 輸出:[(0, 10), (1, 20), (2, 30)]
3. 自定義 start:適配題目索引要求
部分題目要求索引從 1 開始(如 “第 k 個(gè)元素”),只需設(shè)置 start=1:
nums = [5, 3, 8]
# start=1 讓索引從1開始,符合題目“第k個(gè)元素”的表述習(xí)慣
for idx, val in enumerate(nums, start=1):
print(f"第 {idx} 個(gè)元素:{val}") # 輸出:第1個(gè)元素:5,第2個(gè)元素:3...四、使用 enumerate 的注意事項(xiàng)
- 索引是 “遍歷順序” 而非 “原數(shù)組實(shí)際索引”:若遍歷的是切片 / 過濾后的數(shù)組,索引是相對(duì)索引,而非原數(shù)組索引:
nums = [1, 2, 3, 4] # 遍歷切片 nums[2:](元素是3、4),enumerate 的索引從0開始,而非原數(shù)組的2 for idx, val in enumerate(nums[2:]): print(idx, val) # 輸出:0 3;1 4 - 不要遍歷中修改原對(duì)象:與普通 for 循環(huán)同理,遍歷 List / 矩陣時(shí)增刪元素,會(huì)導(dǎo)致枚舉異常;
- 多維數(shù)組注意索引層級(jí):嵌套 enumerate 時(shí),外層
i是行索引,內(nèi)層j是列索引,避免混淆。
到此這篇關(guān)于Python 中 enumerate 函數(shù)的妙用的文章就介紹到這了,更多相關(guān)Python enumerate 函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python中enumerate函數(shù)及其應(yīng)用詳解
- Python中enumerate()函數(shù)詳細(xì)分析(附多個(gè)Demo)
- Python中的enumerate函數(shù)使用方法詳解
- python?使用enumerate()函數(shù)詳解
- 詳解Python中enumerate函數(shù)的使用
- Python中的枚舉函數(shù)enumerate()的具體用法
- python enumerate內(nèi)置函數(shù)用法總結(jié)
- Python range、enumerate和zip函數(shù)用法詳解
- python中enumerate() 與zip()函數(shù)的使用比較實(shí)例分析
相關(guān)文章
Python高效生成requirements.txt的兩種方法
Python項(xiàng)目依賴管理是開發(fā)流程中的關(guān)鍵環(huán)節(jié),requirements.txt文件作為記錄項(xiàng)目依賴的標(biāo)準(zhǔn)方式,能確保環(huán)境一致性并簡(jiǎn)化協(xié)作部署流程,掌握其生成方法對(duì)開發(fā)者至關(guān)重要,本文給大家介紹了兩種高效生成requirements.txt的方法,需要的朋友可以參考下2025-12-12
Python根據(jù)URL地址下載文件并保存至對(duì)應(yīng)目錄的實(shí)現(xiàn)
這篇文章主要介紹了Python根據(jù)URL地址下載文件并保存至對(duì)應(yīng)目錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Python編程中*args與**kwargs區(qū)別作用詳解
這篇文章主要介紹了Python編程中*args與**kwargs區(qū)別作用詳解2021-10-10
Python使用socket實(shí)現(xiàn)組播與發(fā)送二進(jìn)制數(shù)據(jù)
在工作中經(jīng)常會(huì)用到socket傳輸數(shù)據(jù),例如客戶端給服務(wù)器發(fā)送數(shù)據(jù)(雙方約定了數(shù)據(jù)格式),本文主要介紹了Python使用socket實(shí)現(xiàn)組播與發(fā)送二進(jìn)制數(shù)據(jù),感興趣的可以了解一下2021-06-06
Python實(shí)戰(zhàn)之實(shí)現(xiàn)康威生命游戲
這篇文章主要介紹了Python實(shí)戰(zhàn)之實(shí)現(xiàn)康威生命游戲,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)python的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04
python獲取外網(wǎng)ip地址的方法總結(jié)
這篇文章主要介紹了python獲取外網(wǎng)ip地址的方法,實(shí)例總結(jié)了四種常用的獲取外網(wǎng)IP地址的技巧,需要的朋友可以參考下2015-07-07

