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

