LeetCode Q33-Q35練習筆記 (Python3) 二分法查詢
LeetCode Q33-Q35
- Q33 搜尋旋轉排序陣列 Search in Rotated Sorted Array
- Q34 在排序陣列中查詢元素的第一個和最後一個位置 Find First And Last Position of Element in Sorted Array
- Q35 搜尋插入位置
- Q33 - Q35 一些筆記
Q33 搜尋旋轉排序陣列 Search in Rotated Sorted Array
升序排列的整數陣列 nums 在預先未知的某個點上進行了旋轉(例如, [0,1,2,4,5,6,7] 經旋轉後可能變為 [4,5,6,7,0,1,2] )。
請你在陣列中搜索 target ,如果陣列中存在這個目標值,則返回它的索引,否則返回 -1 。
這道題我是根本沒有看懂啊,看到很多評論是用二分法做的,但是由於這道題也沒有要求時間複雜度O(logn),我就用自己的方法寫了
class Solution:
def search(self, nums: List[int], target: int) -> int:
return nums.index(target) if target in nums else -1
這種使用內建函式的當然是不對的。。。
Q34 在排序陣列中查詢元素的第一個和最後一個位置 Find First And Last Position of Element in Sorted Array
給定一個按照升序排列的整數陣列 nums,和一個目標值 target。找出給定目標值在陣列中的開始位置和結束位置。
如果陣列中不存在目標值 target,返回 [-1, -1]。
進階:
你可以設計並實現時間複雜度為 O(log n) 的演算法解決此問題嗎?
這道題既然提出了時間複雜度的要求,那麼就是要求使用二分法來做這道題。我也很久沒有使用過這個方法了,好好的複習了一下。二分法大致是用在已經排序過的陣列中,通過判斷中間值與目標值的大小來分割判斷區域,從而快速的查詢到目標值。由於這道題需要找兩個邊界值,那麼就需要用到兩次二分法,時間複雜度為O(log2n).
下面這段程式碼是我根據一個java程式碼修改的,但是我並不是很能理解他的思路
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
lst=[-1,-1]
left=0
right=len(nums)-1
if not nums:
return lst
while left<right: #第一輪查詢
mid=(left+right)//2 #對於python兩種寫法都是可以的
if nums[mid]>=target: #找左邊界,即位置最低的target
right=mid #由於可以等於target的時候查詢,所以分邊界可以讓right等於mid
else:
left=mid+1
if nums[left]==target: #判斷是否查詢到了目標值,如果沒有就直接返回[-1,-1]
lst[0],lst[1]=left,left
else:
return lst
#此時left與right已經發生了改變
right=len(nums) #此時left沒有改變,仍然是作為左邊界的索引
while left<right: #第二輪查詢
mid = (left+right)//2
if nums[mid]<=target:
left=mid+1
else:
right=mid
lst[1]=left-1
return lst
這道題不能幹寫,需要明白的是查詢的第一個左邊界指的是第一個等於target的數的位置,右邊界指的是第一個大於target的數的位置減一,當然,這一切的前提在於題目提供的是升序陣列,若是倒序或者是亂序就另當別論了
我在題解裡面看到了一個人用python寫的,感覺更加容易理解。他先是將二分法作為函式然後呼叫便可以了,最後a的結果就是第一個等於target
的數的位置,b
的結果就是第一個大於target
的數的位置,所以最後答案需要將b-1
class Solution(object):
def searchRange(self,nums, target):
def left_func(nums,target):#二分法函式
n = len(nums)-1
left = 0
right = n
while(left<=right):
mid = (left+right)//2
if nums[mid] >= target:
right = mid-1
if nums[mid] < target:
left = mid+1
return left
a = left_func(nums,target)
b = left_func(nums,target+1)
#當索引值等於陣列長度意味著該數比陣列中所有數都大(因為索引最大值為len(nums)-1),也就不會存在於陣列中
if a == len(nums) or nums[a] != target:
return [-1,-1]
else:
return [a,b-1]
但是看完這兩種方法的程式碼我又暈了,為什麼在二分法查詢階段,第一個程式碼中是讓right=mid
,而第二個程式碼中是讓right=mid-1
?之後發現原因出在他們的while迴圈條件,如果條件是<
,那麼便是right=mid
;如果條件是<=
,那麼便是right=mid-1
同時,這兩種方法中的二分法while迴圈時並沒有return任何值,這就會導致迴圈會一直持續,直到最後所查詢的索引值為left。
Q35 搜尋插入位置
給定一個排序陣列和一個目標值,在陣列中找到目標值,並返回其索引。如果目標值不存在於陣列中,返回它將會被按順序插入的位置。
你可以假設陣列中無重複元素。
這道題基本就是最基礎的二分法查找了,程式碼如下:
def binarySearch(nums, target):
left=0
right=len(nums)-1
while left<right:
mid=(left+right)//2
if nums[mid]>target: #說明目標值target在nums[mid]左邊,將右邊界縮小
right=mid
elif nums[mid]<target: #說明目標值target在nums[mid]右邊,將右邊界增大
left = mid + 1
else:
return mid #返回查詢的目標值在陣列中的索引
return left
Q33 - Q35 一些筆記
- 二分法基本程式碼:
def binarySearch(nums, target):
left=0
right=len(nums)-1
while left<right:
mid=(left+right)//2
if nums[mid]>target: #說明目標值target在nums[mid]左邊,將右邊界縮小
right=mid
elif nums[mid]<target: #說明目標值target在nums[mid]右邊,將右邊界增大
left = mid + 1
else:
return mid #返回查詢的目標值在陣列中的索引
- 二分法的while迴圈條件中,如果條件是
<
,那麼便是right=mid
;如果條件是<=
,那麼便是right=mid-1
- 二分法while迴圈時如果沒有return任何值,這就會導致迴圈會一直持續,直到最後所查詢的索引值為left。
mid=(left+right)//2
和mid=left+(right-left)//2
都行,注意python中一定要用到//
整除