Pythonで解く「最初の不良バージョン」問題:二分探索による効率的なアプローチ
問題の概要
ある会社で、プロダクトマネージャーが新しい製品を開発するチームを率いているとします。最新バージョンが品質チェックに不合格となった場合、各バージョンは前のバージョンをベースに開発されているため、不良バージョン以降のすべてのバージョンも不良になると仮定できます。
そこで、n個の要素を持つ配列 A = [1, 2, …, n] が与えられたとき、この中から最初の不良バージョンを見つける必要があります。
ここでは、指定されたバージョンが不良かどうかを判定する関数 isBadVersion(version_id) が用意されているものとします。例えば、n = 5 でバージョン4が最初の不良バージョンである場合、isBadVersion(3) は False を返し、isBadVersion(4) と isBadVersion(5) は True を返します。このとき、最初の不良バージョンは 4 です。
解法のアプローチ
この問題を解くには、以下の手順に従います。
- n < 2 の場合は、そのまま n を返す
isBadVersion関数を活用し、二分探索(バイナリサーチ)によって不良バージョンを検出する
先頭から順に調べる線形探索では O(n) の計算量が必要ですが、二分探索を使えば O(log n) で効率的に最初の不良バージョンを特定できます。
実装例
以下の実装例を見て、理解を深めましょう。
first_bad = 0
def isBadVersion(version):
if version >= first_bad:
return True
return False
class Solution:
def firstBadVersion(self, n):
if n < 2:
return n
start = 1
end = n
while(start <= end):
mid = (start + end) // 2
if isBadVersion(mid) and not isBadVersion(mid - 1):
return mid
elif isBadVersion(mid - 1):
end = mid - 1
else:
start = mid + 1
ob1 = Solution()
first_bad = 4
op = ob1.firstBadVersion(5)
print(op)
入力
5 4
出力
4
コードの解説
このアルゴリズムの動作を順を追って説明します。
- 初期化: 探索範囲の始点
startを 1、終点endを n に設定します。 - 二分探索:
startがend以下である間、中央の値midを計算します。 - 境界の判定:
midが不良バージョンであり、かつmid - 1が正常なバージョンであれば、midこそが最初の不良バージョンなので即座に返します。 - 範囲の絞り込み:
mid - 1も不良バージョンであれば、答えは左側にあるためendをmid - 1に更新します。そうでなければ答えは右側にあるため、startをmid + 1に更新します。
このように、ループごとに探索範囲を半分に絞り込むことで、O(log n) の時間計算量で最初の不良バージョンを効率的に見つけられるのが、この手法の大きな強みです。
-
Pythonのファーストクラス関数(第一級関数)とは?基本と使い方を解説
多くのプログラミング言語において、「ファーストクラスオブジェクト(第一級オブジェクト)」とは、統一的な方法で扱うことのできるオブジェクトを指します。ファーストクラスオブジェクトは、データ構造として格納したり、他の関数の引数として渡したり、制御構造の中で利用したりできます。 Pythonでは関数もこのようなオブジェクトとして扱われ、ファーストクラスオブジェクトのすべての性質を満たす場合、その関数はファーストクラス関数(第一級関数)であると言えます。 ファーストクラス関数の主な性質 Object型のインスタンスである 変数として代入・保存できる 他の関数の引数として渡せる 関数の戻り値として別の
-
Pythonモジュールのバージョンを確認する方法【pip freezeと__version__の使い方】
Pythonをインストールすると、パッケージ管理ツールであるpipも一緒にインストールされます。pipを使えば、インストール済みのPythonモジュール(パッケージ)のバージョンを簡単に確認できます。この記事では、代表的な確認方法を目的別にわかりやすく解説します。 1. インストール済みの全モジュール一覧を表示する(pip freeze) すべてのインストール済みモジュールとそのバージョン番号を一覧表示したい場合は、以下のコマンドを実行します。 $ pip freeze 実行すると、次のような出力が得られます。 asn1crypto==0.22.0 astroid==1.5.2 attrs=