LeetCode 面試題 08.03. 魔術索引 | Python
面試題 08.03. 魔術索引
題目來源:力扣(LeetCode)
題目
魔術索引。 在陣列A[0…n-1]中,有所謂的魔術索引,滿足條件A[i] = i。給定一個有序整數陣列,編寫一種方法找出魔術索引,若有的話,在陣列A中找出一個魔術索引,如果沒有,則返回-1。若有多個魔術索引,返回索引值最小的一個。
示例1:
輸入:nums = [0, 2, 3, 4, 5]
輸出:0
說明: 0下標的元素為0
示例2:
輸入:nums = [1, 1, 1]
輸出:1
說明:
- nums長度在[1, 1000000]之間
- 此題為原書中的 Follow-up,即陣列中可能包含重複元素的版本
解題思路
思路:剪枝,分治
這裡先提一下,只是看本題的話,可能會有些爭議,後面再解釋。
現在先審題,理清其中的關鍵點:
- 給定的陣列是有序的(題目中只說有序,並未說是升序還是降序,這裡結合示例,先預設是升序);
- 題目要求的魔術索引,即是滿足條件 A[i] = i;
- 陣列中可能存在多個魔術索引,存在時,返回索引值最小的;
- 不存在魔術索引,則返回 -1。
現在,結合上面羅列的關鍵點,可以發現陣列有序(前面說了先預設升序),即使存在多個魔術索引,返回的也是最小索引的一個。那麼現在能直接想到的就是直接遍歷陣列,當滿足條件 nums[i]==i
,直接返回即可,沒有就返回 -1。相關程式碼大致如下:
class Solution:
def findMagicIndex(self, nums: List[int]) -> int:
for i in range(len(nums)):
if nums[i] == i:
return nums[i]
return -1
就前面開篇說的爭議,稍微吐槽下,當寫完上面段程式碼時,總覺得事情沒那麼簡單。後面去翻閱了官方題解下的評論,的確有很大的爭議。
這裡大致說下,只看本題的話,最直觀的就是直接遍歷,暴力法解決。可以回顧下題目,題目最後的說明中提及到 【此題為原書中的 Follow-up,即陣列中可能包含重複元素的版本】。
這裡說的是此題是可能存在重複元素的版本,所以筆者也去翻閱了原題。查閱的結果是,原題是有兩部分:
- 一個是給定陣列升序,元素值各不相同,要求給定的陣列中是否存在魔術索引;
- 另一個是給定不下降序列,元素值可能相同,求是否存在魔術索引。(也就是本題)
而且題目中 說明:思考是否存在一個複雜度優於 O(n) 的方法。
那麼就現在就查閱的資料結合本題,進行展開說明。
這裡,在原題第一部分的基礎上,重新來看這題。題目中說明,【有可能存在多個魔術索引,元素可能重複】。那我們將情況分開討論:
- 首先先討論,當只有一個魔術索引時。
我們先假設存在魔術索引 i,那麼也就意味著 [0, i-1] 這個區間中,索引對應的值均小於索引值,而 [i+1, n-1] 這個區間的索引對應的值則均大於索引值。我們舉個例子來說明,例如給定如下陣列:
nums = [-1, 0, 1, 3, 5]
那麼,上面陣列中每個索引對應的元素值與索引的差值如下:
[-1, -1, -1, 0, 1]
可以看到,上面的陣列是具有單調性的,那麼我們只要使用二分查詢,找到 0 所在的位置,返回答案即可。
- 再看可能存在多個魔術索引的情況,這裡也同樣將可能重複的情況引入進來。
假設存在這樣的一個陣列
nums = [0, 0, 1, 1, 4, 6]
還是按照前面的策略,用元素值減去元素對應的索引,得:
[0, -1, -1, -2, 0, 1]
現在,我們可以看到,結果並不具備單調性,在這裡不能夠直接用二分查詢的方法去解決。在這裡,我們要進行適當的剪枝,具體的做法如下:
- 同樣還是先取中間元素,如果中間元素剛好是魔術索引,這個時候要注意,因為有可能有多個魔術索引,當前的魔術索引並不是最小的那個。但是我們可以確定的是,中間元素右側的索引值較大,即使存在魔術索引也不是更小的那個,那麼此時可以拋開右側部分,轉而去查詢左側部分是否還有更小的魔術索引。
- 如果中間元素不是魔術索引,這裡無法確定魔術索引可能存在於哪側。這個時候,兩邊都要進行搜尋。
在這裡,根據上述的做法,我們用遞迴的方法去搜尋。
具體程式碼實現如下(含註釋)。
再囉嗦一句,其實到最後,使用遞迴的方法,也是往左側找答案,反而有可能影響效率。不過,這也是一種方法,當然也可以不追究原題如何,直接一次遍歷查詢答案。
程式碼實現
class Solution:
def findMagicIndex(self, nums: List[int]) -> int:
return self.find_magic_index(nums, 0, len(nums) - 1)
def find_magic_index(self, nums, left, right):
# 未找到的符合要求的返回 -1
if left > right:
return -1
# 取中間元素
mid = left + (right - left) // 2
# 先看是否能找到第一個魔術索引,先往左側找
left_ans = self.find_magic_index(nums, left, mid-1)
# 如果左側存在,那麼返回 left_ans
if left_ans != -1:
return left_ans
# 如果不存在,先比較 nums[mid] == mid
elif nums[mid] == mid:
return mid
# 不存在,且 nums[mid] != mid 時,往右側尋找
return self.find_magic_index(nums, mid + 1, right)
實現結果
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4548/viewspace-2825977/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python 魔術方法指南Python
- Python 魔術方法 - Magic MethodPython
- python中的魔術方法__Python
- python魔術方法詳解Python
- Python 中的魔術方法詳解Python
- Python中的魔術方法詳解Python
- [網路流24題] 魔術球問題 (最大流)
- PHP魔術方法和魔術常量介紹及使用PHP
- PHP 魔術方法PHP
- PHP魔術方法PHP
- python面試題Python面試題
- 拼多多筆試題(一):多多的魔術盒子筆試
- LeetCode 面試題01.06LeetCode面試題
- PHP中的魔術方法和魔術常量簡介和使用PHP
- php 魔術方法 __callPHP
- PHP中什麼是魔術常量?有哪些魔術常量?(總結)PHP
- python面試題(一)Python面試題
- Python 常用面試題Python面試題
- Python面試題庫Python面試題
- python面試題目Python面試題
- Python魔術方法 __getattr__、__getattribute__使用詳解Python
- Python很簡單?學會魔術方法才算入門!Python
- 昨天去面試,這5個Python面試題都被考到了,Python面試題No6Python面試題
- PHP 魔術常量簡要PHP
- #魔術方法(會話管理)會話
- 中聯綠盟面試技術題面試
- python 魔術方法 : 讓自定義類更像內建型別Python型別
- leetcode-面試經典150題LeetCode面試
- python後端面試題Python後端面試題
- Python 筆試 面試題Python筆試面試題
- 面試題:MySQL索引為什麼用B+樹?面試題MySql索引
- 索引@oracle索引技術索引Oracle
- 用 Python 的魔術方法做出更好的正規表示式 APIPythonAPI
- 詳解Python魔術方法__getitem__、__setitem__、__delitem__、__len__Python
- 週三面試Python開發,這幾道Python面試題差點答錯,Python面試題No7Python面試題
- Python面試50題!面試鞏固必看!【轉】Python面試
- Matlab轉python的索引問題MatlabPython索引
- 怎樣回答技術面試題?面試題