Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions 0278.First-Bad-Version/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# 278. First Bad Version

## step1

二分探索。5分未満。

list(range(1, n+1))を書いてメモリエラー。nが巨大なため。
bisect_leftの引数は range でも良い。ソート済みの`collections.abc.Sequence`。


## step2

https://github.com/huyfififi/coding-challenges/pull/14#pullrequestreview-2830537270

- `left_i` の `i` は index の略なら省略しない方がよいが、二分探索では `left` / `right` / `mid` が慣用的

>left, right もよく使われるのですが、本当はいい名前ではあまりないです。
>
>二分探索をする仕事をシフト制でやるとして、職場に行ってみたら「左が100で右が200」とだけ書いてある業務日誌があったら昨日働いていた人に電話しませんか。「左と右ってどういう意味なのか。」
>
>つまり、本当は、「左が100」で表現したいことは「..., 98, 99 までは good を確認したが 100 とそれ以降は未確認」であり、「右が200」で表現したいことは「200, 201,... が bad は確認したが 199 とそれ以前は未確認」ということです。このような業務日誌ならば電話しなくて済みそうです。
>
>また、プロジェクト開始前のブリーフィングで、日誌の「左が100」の意味を上のように決めておけば、はじめのように電話しなくていいわけです。

二分探索で大事なのは、変数名そのものよりも「その時点で何が確定しているか」という不変条件。

`left` / `right` だけでは「何が確定済みで、何が未確認か」は分からない。ループ不変条件として、どの範囲が good 確定で、どの範囲が bad 確定かを意識する





https://github.com/naoto-iwase/leetcode/pull/68/changes


11 changes: 11 additions & 0 deletions 0278.First-Bad-Version/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import bisect

# The isBadVersion API is already defined for you.
# def isBadVersion(version: int) -> bool:


class Solution:
def firstBadVersion(self, n: int) -> int:
return (
bisect.bisect_left(range(1, n + 1), True, key=lambda x: isBadVersion(x)) + 1
)
17 changes: 17 additions & 0 deletions 0278.First-Bad-Version/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# The isBadVersion API is already defined for you.
# def isBadVersion(version: int) -> bool:


class Solution:
def firstBadVersion(self, n: int) -> int:
left = 1
right = n + 1

while left < right:
middle = left + (right - left) // 2
if not isBadVersion(middle):
left = middle + 1
else:
right = middle

return left