-
Pythonで文字列内の重複しない部分文字列の個数を求めるプログラム
問題の概要 ある文字列 s が与えられたとします。ここでの課題は、s から取り出せるすべての部分文字列のうち、重複しないもの(ユニークなもの)だけを抽出し、その総数を出力することです。 たとえば、入力が s = prrstvt の場合、出力は 26 になります。 このとき得られる重複しない部分文字列は、以下の26種類です。 pr、rrs、st、rr、tv、rstv、stvt、prrstv、prrstvt、rrstvt、s、prrst、stv、rrstv、rst、v、tvt、rstvt、r、rs、vt、t、prr、p、rrst、prrs 解法の考え方 この問題は、「各位置で終わる部分文字列」を順
-
Pythonでスターグラフの中心ノードを見つけるプログラム
スターグラフとはスターグラフ(スター・グラフ)とは、1つの中心ノードと、その中心ノードを他のすべてのノードに接続するちょうど n - 1 本の辺から構成される無向グラフです。n 個のノードには 1 から n までのラベルが付けられています。この記事では、与えられたスターグラフの中心ノードを見つけるプログラムを Python で実装します。例えば、次のようなグラフが入力として与えられた場合を考えてみましょう。この場合、ノード 3 がすべての辺に共通して現れる中心であるため、出力は 3 となります。解法のアプローチスターグラフの性質上、中心ノードはすべての辺に出現します。一方、それ以外のノードはそ
-
Pythonで顧客の平均待ち時間を求めるプログラムの実装方法
レストランのキッチンをシミュレートする古典的なアルゴリズム問題を考えてみましょう。配列 customers があり、その各要素 customers[i] は [arrival_i, time_i] というペアを表しています。arrival_i は i 番目の顧客の到着時刻(昇順にソート済み)、time_i はその顧客の注文を準備するために必要な時間です。 顧客が到着すると注文を行いますが、その注文の調理はコックが手空きになったときにのみ開始されます。コックは同時に複数の顧客の料理を作ることができず、必ず注文された順番どおりに調理を行います。このとき、全顧客の平均待ち時間を求めるのがこの問題の目
-
Pythonで最大の平均合格率を求めるプログラム(ヒープを使った貪欲法)
問題の概要クラスのリストが与えられ、classes[i] は [pass_i, total_i] という形式で表されます。ここで pass_i は i 番目のクラスで試験に合格した生徒の数、total_i はそのクラスの生徒の総数です。さらに extra という値も与えられます。これは、どのクラスに配属されても必ず試験に合格できることが保証されている「優秀な追加生徒」の人数を意味します。私たちの課題は、これらの追加生徒を各クラスへ割り当てることで、全クラスの平均合格率を最大化することです。クラスの合格率は「そのクラスで合格する生徒数 ÷ クラスの総生徒数」で求められ、平均合格率は「全クラスの合
-
Pythonで操作を繰り返した後に得られる最大のバイナリ文字列を求めるプログラム
ここでは、あるバイナリ文字列(0と1だけで構成された文字列)が与えられたとき、次の2種類の操作を何回でも適用できるものとして、最終的に得られる数値として最大のバイナリ文字列を求める方法を解説します。文字列に部分文字列 00 が含まれる場合、それを 10 に置き換えられる。文字列に部分文字列 10 が含まれる場合、それを 01 に置き換えられる。問題の例たとえば入力が s = 001100 の場合、出力は 111011 になります。実際には、次のように文字列を変形できます。(00)1100 → 101(10)0 → 1010(10) → 10(10)01 → 100(10)1 → 1(00)01
-
Pythonで桁を並べ替えて2の累乗を作れるか判定するプログラム
正の整数 N が与えられたとします。この数の桁を任意の順序に並べ替え(元の順序のままでも可)、先頭の桁が0にならないようにします。そして、その結果得られる数が2の累乗になるようにできるかどうかを判定する必要があります。例えば、入力が N = 812 の場合、出力は True となります。これは「812」の桁を並べ替えると「128」(= 27)を作れるためです。解法のアプローチこの問題を解く鍵となるのは、「桁を並べ替えた数同士は、ソート後の桁の並びが必ず一致する」という性質です。つまり、ある数がNの桁を並べ替えたものであるかを調べるには、両者を文字列に変換して文字をソートし、一致するかどうかを比
-
【Python】腐る前に食べられるリンゴの最大数を求めるアルゴリズム(最小ヒープで解く)
同じ長さ n の2つの配列 days と apples があるとします。ある特別なリンゴの木が n 日間連続でリンゴを実らせます。i 日目には apples[i] 個のリンゴがなり、それらは days[i] 日後に腐ります。言い換えると、i + days[i] 日目にはそのリンゴは腐って食べられなくなります。また、apples[i] = 0 かつ days[i] = 0 の場合は、i 日目には新しいリンゴが実らないことを表します。 1日に食べられるリンゴは最大1個です(最初の n 日が過ぎても、腐っていないリンゴが残っていれば食べ続けられます)。このとき、最終的に食べられるリンゴの最大数を求め
-
Pythonで解く!おいしさの合計が2のべき乗になる2品の組み合わせ(良い食事)を数える方法
問題概要配列 deli が与えられ、deli[i] は i 番目の食品のおいしさを表します。このリストから作れる「良い食事」の総数を求めるのが目的です。ここで「良い食事」とは、ちょうど2つの異なる食品を選び、そのおいしさの合計が2のべき乗になる食事のことです。答えが非常に大きくなる可能性があるため、結果は 10^9 + 7 で割った余りを返します。例えば、入力が deli = [1, 7, 3, 6, 5] の場合、出力は 3 になります。これは、(1, 3)、(1, 7)、(3, 5) の3組のペアについて、おいしさの合計がそれぞれ 4、8、8 となり、いずれも2のべき乗に一致するためです。
-
Pythonで蛇と梯子ゲームの最短手数を求める方法|BFSを使った実装例
「蛇と梯子(Snakes and Ladders)」は、サイコロを振ってマスを進み、梯子に掛かれば一気に上へ、蛇にかまれれば下へ戻される古典的なボードゲームです。本記事では、このゲームをPythonで解き、ゴールであるマス100に到達するまでに必要な最小のサイコロ振り回数を求めるプログラムを紹介します。 問題の概要 ここでは特別なルールとして、サイコロの出目を1〜6の中から自由に選べるものとします。スタート地点はマス0、目的地はマス100です。盤面上の蛇と梯子の位置情報が与えられたとき、目的地に到達するために必要な最小のダイスロール回数を求めます。 配列 snakes と ladders は
-
Pythonでプリムのアルゴリズムを使って最小全域木(MST)を求める方法
最小全域木(MST)とは?グラフが与えられたとき、そこから「最小全域木」(MST:Minimum Spanning Tree)を求めることを考えます。グラフのMSTとは、重み付きグラフの部分集合であり、すべての頂点が含まれており互いに接続され、かつ部分集合内に閉路(サイクル)が存在しないものを指します。「最小」と呼ばれるのは、MSTの辺の重みの合計が、元のグラフから構成できるどの全域木よりも小さくなるためです。この記事では、プリム(Prim)のMSTアルゴリズムを実装し、与えられたグラフからMSTの辺の重みの合計を求める方法を解説します。問題の例たとえば、次のようなグラフが入力として与えられた
-
Pythonで配列を3つの部分配列に分割する有効な方法の数を求めるプログラム
問題の概要 整数要素からなる配列 nums が与えられます。この配列を3つの部分配列に分割する「良い分割(good split)」の総数を求めましょう。答えは非常に大きな値になる可能性があるため、結果は 109 + 7 で割った余りとして返します。 ここで「良い分割」とは、配列を左から右へ向かって3つの空でない連続した部分配列(左・中央・右)に分け、次の条件を両方とも満たす分割のことです。 左側の要素の合計 ≦ 中央の要素の合計 中央の要素の合計 ≦ 右側の要素の合計 具体例 たとえば、入力が nums = [2,3,3,3,7,1] の場合、出力は 3 になります。条件を満たす分割方法
-
Pythonでグラフ内の最大クリークの最小サイズを求めるプログラム
問題概要 グラフが与えられたとき、そのグラフに含まれる最大クリークの最小サイズを求める問題を考えます。ここで「クリーク」とは、グラフの頂点部分集合のうち、任意の2つの頂点が必ず隣接している(つまり、すべての頂点ペア間に辺が存在する)ものを指します。 最大クリークを求める問題は多項式時間では解けないことが知られているため(NP困難問題)、小規模なグラフについてノード数とエッジ数が与えられた場合には、工夫したアルゴリズムで最大クリークのサイズを導き出す必要があります。 例えば、入力が nodes = 4、edges = 4 の場合、出力は 2 となります。このグラフでは、クリークの最大サイズは 2
-
ペナルティが最小となるグラフ内の2頂点間のパスを見つけるPythonプログラム
問題概要 無向の重み付きグラフが与えられ、ノード a からノード b へ至る「最小ペナルティ」のパスを求めることを考えます。ここでいうパスのペナルティとは、そのパスに含まれるすべての辺の重みをビット単位OR(論理和)で結合した値のことです。つまり、ペナルティが最小となるパスを見つけ出し、もし2つのノード間にパスが存在しない場合は -1 を返す必要があります。 具体例 たとえば、次のようなグラフが与えられたとします。 始点 s = 1、終点 e = 3 のとき、出力は 15 になります。 頂点1と頂点3の間には2つのパスが存在します。最適なパスは 1 → 2 → 3 であり、このパスのコストは
-
【Python】最小の頂点から最大の頂点までの最小コスト経路を求めるアルゴリズム
問題の概要 重み付き無向グラフが与えられ、あるノードから別のノードへ移動するときのコストが最小となる経路を見つけることを考えます。移動コストは次のように計算されます。たとえば、頂点Aから頂点Cへ向かう経路が A → B → C であるとき、AからBへの移動コストが10、BからCへの移動コストが20だとします。このとき、AからCまでの合計コストは「AからBまでの移動コスト」に「BからCへの移動コストと、Bまでに累積したコストとの差」を加えたものになります。つまり、10 + (20 − 10) = 20 となります。 求めるのは、グラフ内で最も小さい番号を持つノード(頂点1)から、最も大きい番号
-
Pythonで特定のグラフから特別なタイプのサブグラフを見つけるプログラム
ここでは、「ヘッド(head)」と「フィート(feet)」という2種類の頂点を持つ特殊なグラフを考えます。このグラフにはヘッドがちょうど1つだけ存在し、k本の辺によってヘッドがそれぞれのフィートへ接続されています。入力として無向・非重み付きグラフが与えられたとき、そのグラフの頂点素な部分グラフ(vertex disjoint subgraph)の中から、こうした特殊なグラフを見つけ出します。2つのグラフが「頂点素」であるとは、互いに共通の頂点を1つも持たないことを意味します。たとえば、次のようなグラフが与えられたとします。ノード数(n)= 6、フィート数(t)= 2 の場合、出力は 5 になり
-
Pythonですべての手紙を配達するための最小パスを見つけるプログラム
問題の概要n個の都市がn−1本の道路で相互に接続されているとします。この構成では、どの都市からでも他のすべての都市へ移動できます。都市の郵便システムでは毎日k通の手紙を配達しており、その宛先はk個の異なる都市のいずれかです。郵便配達員は毎日、これらすべての手紙を宛先の住所へ届けなければなりません。ここで求めたいのは、すべての手紙を配達し終えるまでに配達員が移動しなければならない距離の最小値です。なお、配達員は任意の都市から出発することができます。たとえば、次のような入力が与えられたとします。手紙を配達すべき都市(delv)が1、2、4である場合、出力は4になります。配達員は都市1、2、4のいず
-
Pythonで部分文字列を削除して最大スコアを求めるプログラムの解説
問題概要文字列 s と2つの整数値 x、y が与えられているとします。次の2種類の操作を任意の回数だけ実行できます。部分文字列「ab」を検索し、存在する場合はそれを削除して x ポイントを獲得する。部分文字列「ba」を検索し、存在する場合はそれを削除して y ポイントを獲得する。これらの操作を文字列 s に適用した後、獲得できる最大ポイントを求めるのが目的です。具体例たとえば、入力が s = cbbaacdeabb、x = 4、y = 5 の場合、出力は 14 になります。その過程は以下の通りです。初期状態の文字列は「cbbaacdeabb」。まず「cbbaacde(ab)b」のように「ab」
-
Pythonでグラフ内の全頂点ペア間の最小コストの合計を求めるプログラム
問題の概要 n個の頂点とm個の辺からなる重み付きグラフを考えます。各辺の重みは2の冪乗(1、2、4、8など)で与えられ、グラフは連結しているため、任意の頂点から任意の頂点へ移動することが可能です。ある頂点ペア間の移動コストは、その経路上の辺の重みの総和として定義されます。 この記事では、すべての頂点ペア間の最小コストの合計を求めるPythonプログラムを紹介します。 入力例と出力 例として、次のようなグラフが与えられたとします。 頂点数 n = 6 の場合、出力は 2696 となります。つまり、すべての頂点ペア間の最短距離を合計すると2696になるということです。 解法のアプローチ この
-
Pythonで都市間のショートカット最短距離を求めるプログラムの実装方法
n個の都市があり、それぞれの都市は「高速道路」と「近道(ショートカット)」という2種類の道路で結ばれているとします。手元の地図には高速道路だけが記載されていて、近道は一切載っていません。都市の運輸部門では、高速道路と近道を活用して各都市を結ぶ交通手段を新設しようと考えています。ここで重要なルールは、「2つの都市の間に高速道路が存在しない場合、その間には必ず近道が存在する」ということです。今回の課題は、出発都市から他のすべての都市までの、近道の利用回数で表した最小距離を求めることです。 たとえば、入力が次のようなケースを考えてみましょう。 開始頂点 s を 1 とした場合、出力は「3 1 2
-
Pythonで辞書式順序で最大の有効なシーケンスを構築するプログラム
問題の概要ある数 n が与えられたとき、以下のすべての条件を満たすシーケンス(数列)を見つけることを考えます。数値 1 はシーケンス内にちょうど1回出現する。2 から n までの各数値は、それぞれ2回ずつ出現する。2 以上 n 以下の各数値 i について、その2つの出現位置の距離はちょうど i である。ここで、シーケンス上の2つの要素 a[i] と a[j] の距離は |j − i| として定義されます。求めるのは、これらの条件を満たすシーケンスの中で辞書式順序で最大のものです。例えば、入力が n = 4 の場合、出力は次のようになります。[4, 2, 3, 2, 4, 3, 1]この結果を確