diff --git a/Python3/35. Search Insert Position.md b/Python3/35. Search Insert Position.md new file mode 100644 index 0000000..e8194bd --- /dev/null +++ b/Python3/35. Search Insert Position.md @@ -0,0 +1,132 @@ +## Step 1. Initial Solution + +- bisect.bisect_leftで答えは得られる +- 自分でこれを実装する + - begin, endの定義は他にもやりようがある + - ここでは[begin, end)で定義している + - begin-1より大きく、endより小さい位置にある + - begin == endになったらその位置に入れてあげれば良い + +```python +class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + def binary_search(begin: int, end: int) -> int: + middle = (begin + end) // 2 + if begin == end or target == nums[middle]: + return middle + if target < nums[middle]: + return binary_search(begin, middle) + if target > nums[middle]: + return binary_search(middle + 1, end) + return binary_search(0, len(nums)) +``` + +### Complexity Analysis + +- 時間計算量:O(log n) +- 空間計算量:O(1) + +## Step 2. Alternatives + +- 他にも書き方を試してみる + - target == nums[middle]をなくす + + ```python + class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + def binary_search(begin: int, end: int) -> int: + middle = (begin + end) // 2 + if begin == end: + return middle + if target <= nums[middle]: + return binary_search(begin, middle) + else: + return binary_search(middle + 1, end) + return binary_search(0, len(nums)) + ``` + + - iterationで解く + + ```python + class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + begin = 0 + end = len(nums) + while begin < end: + middle = (begin + end) // 2 + if target <= nums[middle]: + end = middle + else: + begin = middle + 1 + return begin + ``` + + - 確かにleft, rightの方が良く見かけるのを思い出した + - https://github.com/tokuhirat/LeetCode/pull/41/files#diff-2b5524d310a8ba9fe7670e916be44468c8caec3d8aee64536cda8aa952db07f6R46 + + > pythonではオーバーフローを考慮しなくて良いが、考慮する必要がある言語だと mid = left + (right - left) // 2のようにする。 + > + - https://github.com/hayashi-ay/leetcode/pull/40/files + - これも前にやった気がする + - Pythonのint → Cのlong, Pythonのfloat → Cのdouble + + ```python + import sys + + i = sys.maxsize + print(i) + # 9223372036854775807 + print(i == i + 1) + # False + i += 1 + print(i) + # 9223372036854775808 + + f = sys.float_info.max + print(f) + # 1.7976931348623157e+308 + print(f == f + 1) + # True + f += 1 + print(f) + # 1.7976931348623157e+308 + ``` + +- 今回は一つ一つの数字はユニークだが、連続する場合に前に入れようと思うとtarget == nums[middle]は要注意 + - https://github.com/olsen-blue/Arai60/pull/41/files#diff-912c29ce0f491ca88b1474ced97db89f2d33a36a34cd0f516f5b523e400af176R67 + +## Step 3. Final Solution + +- 閉区間 + +```python +class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + left = 0 + right = len(nums) - 1 + while left <= right: + middle = (left + right) // 2 + if target <= nums[middle]: + right = middle - 1 + else: + left = middle + 1 + return left +``` + +- 開区間 + +```python +class Solution: + def searchInsert(self, nums: List[int], target: int) -> int: + left = -1 + right = len(nums) + while left + 1 < right: + middle = (left + right) // 2 + if target <= nums[middle]: + right = middle + else: + left = middle + return right +``` + +- 反対側の半開区間(-1, len(nums)-1]だけよく分からなかった