diff --git a/0278.First-Bad-Version/memo.md b/0278.First-Bad-Version/memo.md new file mode 100644 index 0000000..1dd295a --- /dev/null +++ b/0278.First-Bad-Version/memo.md @@ -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 + + diff --git a/0278.First-Bad-Version/step1.py b/0278.First-Bad-Version/step1.py new file mode 100644 index 0000000..a0d08f1 --- /dev/null +++ b/0278.First-Bad-Version/step1.py @@ -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 + ) diff --git a/0278.First-Bad-Version/step2.py b/0278.First-Bad-Version/step2.py new file mode 100644 index 0000000..8350590 --- /dev/null +++ b/0278.First-Bad-Version/step2.py @@ -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