diff --git a/33/memo.md b/33/memo.md new file mode 100644 index 0000000..a03192b --- /dev/null +++ b/33/memo.md @@ -0,0 +1,20 @@ +# 33. Search in Rotated Sorted Array + +- 前二問(ソート+循環済み配列の最小値インデックス、単純なtarget探索)に分解できることに気づく +- 練習のためbisectを使わずに書いた +- 二分探索を一回で行う方法はあるのか? + +https://discord.com/channels/1084280443945353267/1233295449985650688/1239594872697262121 +- 二分探索を一回で行う方法を見つけた。賢すぎる。 +- 関数 comp は target との大小で-1, 0, 1の三段階のスコアを振る。しかし循環されているので、これだと昇順にはならない。 +- これを解消するためには、循環で本来の位置より前にきた数字のスコアを下げれば良い。最低どのくらい下げれば良いかというと、compの最大値と最小値との差 1-(-1) = 2である。この係数は-2以下であれば何でも良い。 +- 自分でも空で書いてみる + +https://github.com/hroc135/leetcode/pull/41#discussion_r1970984248 +> 見直したら cmp いらなくて + +なるほど、Pairにすれば解決するのか。自分で思いつきたかったな + +https://github.com/mamo3gr/arai60/blob/33_search-in-rotated-sorted-array/33_search-in-rotated-sorted-array/memo.md + + diff --git a/33/sol1.py b/33/sol1.py new file mode 100644 index 0000000..498e472 --- /dev/null +++ b/33/sol1.py @@ -0,0 +1,33 @@ +class Solution: + def search(self, nums: list[int], target: int) -> int: + if not nums: + return -1 + len_nums = len(nums) + + # Step 1: Find the minimum value + left = 0 # i < left -> nums[i] > nums[-1] + right = len_nums # i >= right -> nums[i] <= nums[-1] + while left < right: + mid = left + (right - left) // 2 + if nums[mid] > nums[-1]: + left = mid + 1 + else: + right = mid + + minimum_index = left + + # Step 2: Find the target + left_in_sorted = ( + 0 # (i - minimum_index) % len_nums < left_in_sorted -> nums[i] < target + ) + right_in_sorted = len_nums # (i - minimum_index) % len_nums >= right_in_sorted -> nums[i] >= target + while left_in_sorted < right_in_sorted: + mid_in_sorted = left_in_sorted + (right_in_sorted - left_in_sorted) // 2 + if nums[(mid_in_sorted + minimum_index) % len_nums] < target: + left_in_sorted = mid_in_sorted + 1 + else: + right_in_sorted = mid_in_sorted + + if nums[(left_in_sorted + minimum_index) % len_nums] != target: + return -1 + return (left_in_sorted + minimum_index) % len_nums diff --git a/33/sol1_revised.py b/33/sol1_revised.py new file mode 100644 index 0000000..a764885 --- /dev/null +++ b/33/sol1_revised.py @@ -0,0 +1,35 @@ +class Solution: + def search(self, nums: list[int], target: int) -> int: + if not nums: + return -1 + len_nums = len(nums) + + # Step 1: Find the minimum value + left = 0 # i < left -> nums[i] > nums[-1] + right = len_nums # i >= right -> nums[i] <= nums[-1] + while left < right: + mid = left + (right - left) // 2 + if nums[mid] > nums[-1]: + left = mid + 1 + else: + right = mid + + minimum_index = left + + # Step 2: Find the target + if nums[-1] < target: + left, right = ( + 0, + minimum_index, + ) + else: + left, right = minimum_index, len_nums + # i < left -> nums[i] < target + # i >= right -> nums[i] >= target + while left < right: + mid = left + (right - left) // 2 + if nums[mid] < target: + left = mid + 1 + else: + right = mid + return left if nums[left] == target else -1 diff --git a/33/sol2.py b/33/sol2.py new file mode 100644 index 0000000..ba29928 --- /dev/null +++ b/33/sol2.py @@ -0,0 +1,24 @@ +import bisect + + +class Solution: + def search(self, nums: list[int], target: int) -> int: + if not nums: + return -1 + len_nums = len(nums) + + # Step 1: Find the minimum value + minimum_index = bisect.bisect_left( + range(len_nums), True, key=lambda x: nums[x] <= nums[-1] + ) + + # Step 2: Find the target + possible_target_index_in_soted = bisect.bisect_left( + range(len_nums), + True, + key=lambda x: nums[(x + minimum_index) % len_nums] >= target, + ) + possible_target_index = ( + possible_target_index_in_soted + minimum_index + ) % len_nums + return possible_target_index if nums[possible_target_index] == target else -1 diff --git a/33/sol3.py b/33/sol3.py new file mode 100644 index 0000000..9ab9621 --- /dev/null +++ b/33/sol3.py @@ -0,0 +1,17 @@ +import bisect + + +class Solution: + def search(self, nums: list[int], target: int) -> int: + if not nums: + return -1 + len_nums = len(nums) + + def comp(a, b): + return (a < b) - (a > b) + + def priority(x): + return (x > nums[-1]) * -2 + comp(target, x) + + possible_index = bisect.bisect_left(nums, priority(target), key=priority) + return possible_index if nums[possible_index] == target else -1