leetcodeの以下の問題で二分探索の勉強をしています。
シンプルな二分探索はできるのですが、以下のような応用的な問題でつまづきます。
leetcodeの問題
以下のようなキレイなコードがディスカッションにいくつも投稿されています。
Python
1def searchRange(self, nums, target): 2 def binarySearchLeft(A, x): 3 left, right = 0, len(A) - 1 4 while left <= right: 5 mid = (left + right) / 2 6 if x > A[mid]: left = mid + 1 7 else: right = mid - 1 8 return left 9 10 def binarySearchRight(A, x): 11 left, right = 0, len(A) - 1 12 while left <= right: 13 mid = (left + right) / 2 14 if x >= A[mid]: left = mid + 1 15 else: right = mid - 1 16 return right 17 18 left, right = binarySearchLeft(nums, target), binarySearchRight(nums, target) 19 return (left, right) if left <= right else [-1, -1]
しかしどれも”left”・"right"を、"mid"で更新していくときに、+1、-1が出てきます。このような実装も理解はできるようになりましたが、それでもコーナーケースの理解はややこしいので、「めぐる式二分探索」というのをwebで学んでから、普段はそれをベースにしていました。ですので、この問題も似たようなパターンで解けないか考えています。ですが、どうしてもうまく行きません。
めぐる式二分探索
私が最初に書いたコードは以下です。
あまりキレイではなく、読みにくくてすみません。
Python
1class Solution: 2 def searchRange(self, nums: List[int], target: int) -> List[int]: 3 # find end 4 left = 0 5 right = len(nums) - 1 6 while right - left > 1: 7 mid = left + ((right - left) // 2) 8 if nums[mid] == target: 9 if mid == right or nums[mid + 1] > target: 10 end = mid 11 break 12 13 if self.isin_left_area(nums[mid], target): 14 right = mid 15 else: 16 left = mid 17 else: 18 end = -1 19 20 # find start 21 left = 0 22 right = len(nums) - 1 23 while right - left > 1: 24 mid = left + ((right - left) // 2) 25 if nums[mid] == target: 26 if mid == left or nums[mid - 1] < target: 27 start = mid 28 break 29 30 if self.isin_right_area(nums[mid], target): 31 left = mid 32 else: 33 right = mid 34 else: 35 start = -1 36 37 return [start, end] 38 39 def isin_left_area(self, mid_val:int, target:int): 40 return mid_val > target 41 42 def isin_right_area(self, mid_val:int, target:int): 43 return mid_val < target 44
ケースとして、nums=[1], target=1やnums=[1, 1, 1], target=1などの場合がうまく行きません。開区間で考えようとすることで、リストnumsの先頭と末尾の判断ができないのが原因と思います。これらのケースは、「めぐる式二分探索」をベースにシンプルな実装をしようと思うと、例外として条件を作るしかないでしょうか。うまく実装できるような方法があれば教えていただきたいです。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/17 08:29
2021/10/22 02:17