二分查找
二分查找的概念
寫這個總結的初衷是4月29日每日一題中「山脈數組中查找目標值」,其中力扣題解對於二分查找做了總結和講解,感覺講的非常好,所以也想記錄下來。
一般題中給出O(logN)時間複雜度或是在有序數組中進行查找,我們通常都會想到二分查找,其實二分查找不一定只能應用於有序數組中,也可以應用於部分有序、旋轉排序數組、山脈數組中。
二分查找是減而治之思想的典型應用:
- 每次都將問題的規模減少,直到問題解決
- 減治思想是分治思想的特例
- 減治思想的應用:雙指針問題、選擇排序算法、TopK問題、二分搜索樹中的查找操作
思路1,在循環體中查找元素
# -*- encoding: utf-8 -*-
"""
@File : binary_search.py
@Time : 2020/4/30 2:46 下午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
"""
def search(nums,left,right,target):
# 在[left,right]中查找
while left<right:
# java等語言中爲防止整型溢出,改爲mid = left + (right - left)/2
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
# 下一輪搜索區間[left,mid-1],向左區間搜索
right = mid - 1
else:
# 下一輪搜索區間[mid+1,right],向右區間搜索
left = mid + 1
return -1
if __name__ == '__main__':
nums = [0,1,2,3,4,5]
print(search(nums,0,len(nums),5))
思路1特點:
- 在區間中只剩一個元素的時候還會執行一遍循環體
- 在循環體內部找目標元素
- 循環體內部的分支通常有3個
在循環體中縮小搜索區間
def search(nums,left,right,target):
while left<right:
# 選擇中位數時下取整
mid = left + (right-left)//2
if check(mid):
left = mid + 1
else:
right = mid - 1
def search_3(nums,left,right,target):
while left<right:
# 選擇中位數時上取整
mid = left + (right-left+1)//2
if check(mid):
right = mid - 1
else:
left = mid + 1
思路2特點:
- 每個分支做的事情都是根據在不斷縮小目標元素的區間
- 當退出循環以後,區間只剩下一個元素,視情況單獨判斷m
1095題:山脈數組中查找目標值
# """
# This is MountainArray's API interface.
# You should not implement it, or speculate about its implementation
# """
#class MountainArray:
# def get(self, index: int) -> int:
# def length(self) -> int:
def binary_search(mountain, target, l, r, key=lambda x: x):
target = key(target)
while l <= r:
mid = (l + r) // 2
cur = key(mountain.get(mid))
if cur == target:
return mid
elif cur < target:
l = mid + 1
else:
r = mid - 1
return -1
class Solution:
def findInMountainArray(self, target: int, mountain_arr: 'MountainArray') -> int:
l, r = 0, mountain_arr.length() - 1
# 尋找峯頂
while l < r:
mid = (l + r) // 2
if mountain_arr.get(mid) < mountain_arr.get(mid + 1):
l = mid + 1
else:
r = mid
peak = l
index = binary_search(mountain_arr, target, 0, peak)
if index != -1:
return index
index = binary_search(mountain_arr, target, peak + 1, mountain_arr.length() - 1, lambda x: -x)
return index
力扣相關題目
這些題目的區別僅在於對於二分查找中判別函數的設計上:
33、81題:搜索旋轉排序數組I、II
prac33
採用思路1三分支
# -*- encoding: utf-8 -*-
"""
@File : prac33.py
@Time : 2020/4/27 8:20 上午
@Author : zhengjiani
@Email : [email protected]
@Software: PyCharm
通過比較端點數據查看子數組是否有序
"""
from typing import List
class Solution:
"""時間複雜度O(logN)"""
def search(self, nums: List[int], target: int) -> int:
if not nums:
return -1
l,r =0,len(nums)-1
while l<=r:
mid = (l + r)//2
if nums[mid] == target:
return mid
# 端點比較驗證子數組是否爲有序數組
if nums[0] <= nums[mid]:
if nums[0] <= target < nums[mid]:
r = mid - 1
else:
l = mid + 1
# 無序
else:
if nums[mid] < target <= nums[len(nums)-1]:
l = mid + 1
else:
r = mid - 1
return -1
if __name__ == '__main__':
# nums = [4,5,6,7,0,1,2]
# target = 0
nums = [3,1]
target = 1
s = Solution()
print(s.search(nums,target))
153、154題:尋找旋轉排序數組中的最小值I、II
69題:平方根
287題:尋找重複數
875題:愛吃香蕉的珂珂
1300題:轉變數組後最接近目標值的數組和
410題:分割數組最大值
其他題還沒做到,等做到再添加進來,就醬~