-
Pythonで木構造内の距離がちょうどkとなる頂点ペアの個数を求める方法
問題の概要 整数 k と、n 個のノードからなる木(ツリー構造)が与えられたとします。このとき、頂点間の距離がちょうど k となる異なる頂点ペアの総数を数えるのが課題です。 例として、k = 2 の場合に次のような木が与えられたとします。 このとき、出力は 4 になります。実際、距離がちょうど 2 となるペアは (1, 3)、(1, 5)、(2, 4)、(3, 5) の 4 組です。 解法の考え方 この問題は、深さ優先探索(DFS)を用いたボトムアップの集計によって効率よく解けます。ポイントは、各頂点ごとに「その頂点から距離 j にある子孫ノードの個数」を記録しておき、部分木を統合しながら
-
Pythonでn×mの長方形内に配置できる2×1サイズの長方形の個数を求める方法
問題概要2つの整数 n と m が与えられたとき、サイズ n × m の長方形の内部に、サイズ 2 × 1 の小さな長方形を最大いくつ配置できるかを求めます。ただし、以下の条件を満たす必要があります。どの2つの小さな長方形も互いに重なってはならない。すべての小さな長方形は、大きな長方形の内部に完全に収まっていなければならない。ただし、外側の長方形の辺に接することは許容される。入力例たとえば、n = 3、m = 3 の場合、出力は 4 になります。3×3のマス目には、2×1の長方形(ドミノ)を4つ配置でき、残りの1マスだけが空きとなります。解き方のアプローチこの問題は、面積の考え方と偶奇の判定を
-
Pythonで時刻tにスタジアムで立っている観客の数を求める方法
スタジアムにはn人の観客がおり、それぞれ1からnまでの番号が付けられています。観客は以下のルールに従って、順番に立ち上がったり座ったりします。 時刻t1に、1番目の観客が立ちます。 時刻t2に、2番目の観客が立ちます。 …… 時刻tkに、k番目の観客が立ちます。 時刻tk+1に、(k+1)番目の観客が立ち、同時に1番目の観客が座ります。 時刻tk+2に、(k+2)番目の観客が立ち、同時に2番目の観客が座ります。 …… 時刻tnに、n番目の観客が立ち、同時に(n−k)番目の観客が座ります。 時刻tn+1に、(n+1−k)番目の観客が座ります。 …… 時刻tn+kに、n番目の観客が座ります。
-
Pythonで最初のN個の自然数の順列から、中央値がMとなる部分配列の個数を求める方法
問題の概要 最初のN個の自然数の順列を並べ替えた配列Aと整数M(ただし M ≤ N)が与えられたとします。このとき、中央値がMとなる部分配列(連続する要素からなる部分列)の個数を求めるのが本記事の目的です。 なお、ここでの中央値とは、数列を昇順にソートした際に中央に位置する要素の値を指します。長さが偶数の数列については、中央に並ぶ2つの要素のうち左側(小さい方)を採用します。 例として、入力が A = [3, 5, 6, 4, 2]、M = 5 の場合を考えてみましょう。条件を満たす部分配列は [3, 5, 6]、[5]、[5, 6]、[5, 6, 4] の4つであるため、答えは 4 となりま
-
C++で依存関係からタスクの実行順序を見つける方法(トポロジカルソート)
問題概要n個の異なるタスクがあるとします。各タスクには0からn-1までのラベルが付けられており、一部のタスクには前提条件(先に完了しておく必要のあるタスク)が存在します。例えば、タスク2を選択したい場合は、まずタスク1を完了していなければなりません。この関係はペア [2, 1] として表現されます。タスクの総数と前提条件ペアのリストが与えられたとき、すべてのタスクを完了できるような実行順序を見つける必要があります。有効な順序が複数存在する場合は、そのうちのどれか1つを返せば構いません。また、与えられたすべてのタスクを完了することが不可能な場合(循環依存が存在する場合)は、空の配列を返します。例
-
行と列の最大値が指定されている場合にPythonで元の行列を復元する方法
問題の概要サイズNの配列AとサイズMの配列B、さらにN×Mの2値行列が与えられているとします。この2値行列では、「1」は元の行列の対応する位置に正の整数が存在していたことを示し、「0」はその位置が元の行列でも0であったことを示します。私たちの課題は、A[i]がi行目の最大要素となり、B[j]がj列目の最大要素となるような元の行列を復元することです。例えば、入力が A = [4, 2, 3]、B = [3, 1, 0, 0, 4, 0, 5] の場合、復元される行列は以下の出力例のようになります。解法のアプローチこの問題を解くためには、以下の手順に従います。N を配列AのサイズとしますM を配列
-
Pythonで解く文字並べ替えゲーム:回文を作れるプレイヤーの勝者を判定するアルゴリズム
問題の概要小文字の英字のみで構成される文字列 S があるとします。この文字列を使って、2人のプレイヤーが次のルールでゲームを行います。どの手番においても、文字列の文字を自由に並べ替えて回文(前から読んでも後ろから読んでも同じになる文字列)を作ることができれば、その手番のプレイヤーの勝ちとなります。回文が作れず、文字を1つ削除しなければならない状況になったプレイヤーは、その時点では勝利できません。両プレイヤーは常に最適な手を選ぶものとし、先手はプレイヤー1です。このとき、ゲームの勝者が誰になるかを求めるのが本記事のテーマです。例えば、入力が「pqpppq」だった場合、答えは Player1 にな
-
Pythonでボールが入る箱の行と列の位置を効率的に求める方法
2つの配列AとBがあるとします。配列Aのサイズは行数を表し、A[i]はi行目に存在する箱の個数を意味します。一方、配列Bはボールの配列であり、B[i]はボールに書かれた番号を表します。各ボールi(値がB[i])は、先頭から数えてB[i]番目の箱に配置されるものとします。このとき、B[i]のそれぞれに対応する箱の「行」と「列」を求めるのが本記事の目的です。 例えば、入力が A = [3, 4, 5, 6]、B = [1, 3, 5, 2] の場合、出力は [(1, 1), (1, 3), (2, 2), (1, 2)] となります。具体的な対応関係は以下の通りです。 B[0] = 1 →
-
Pythonでマルコフ連鎖の特定時刻における状態到達確率を求める方法
マルコフ連鎖のグラフ g が与えられているとします。時刻 t = 0 に状態 S から出発したとき、時刻 T に状態 F へ到達する確率を求めるのが目的です。マルコフ連鎖とは、複数の「状態」と、ある状態から別の状態へ遷移する「確率」から構成される確率過程のことです。これは有向グラフとして表現でき、ノードが状態を、エッジがあるノードから別のノードへ移動する確率を表します。ある状態から別の状態への移動には単位時間がかかり、各ノードの出ていくエッジの確率の合計は必ず 1 になります。問題の例たとえば、N = 6(状態数)、S = 4(開始状態)、F = 2(目標状態)、T = 100(時刻)が入力と
-
Pythonで配列の部分集合の和として表せない最小の正整数を求めるアルゴリズム
昇順にソートされた正の数の配列が与えられたとき、その配列の任意の部分集合の要素の合計として表すことのできない、最小の正の値を見つける必要があります。この問題は O(n) の時間計算量で解くことが求められます。例えば、入力が A = [1, 4, 8, 12, 13, 17] の場合、出力は 2 になります。これは、1 は単独の要素として表せますが、2 はどの部分集合の合計によっても作れないためです。解法のアプローチこの問題は、貪欲法(Greedy法)の考え方を使うことで線形時間で解けます。手順は以下の通りです。n := 配列 A のサイズanswer := 1(初期値)i を 0 から n-1
-
Pythonである文字列内から、別の文字列の全文字を含む最小ウィンドウを検索する方法
問題の概要 2つの文字列 s1 と s2 が与えられたとき、s1 の中から「s2 のすべての文字を含む最小の部分文字列(ウィンドウ)」を見つけます。 たとえば、入力が s1 = I am a student、s2 = mdn の場合、出力は m a studen になります。この部分文字列には m・d・n の3文字がすべて含まれており、これより短い範囲では条件を満たせません。 解法の考え方:スライディングウィンドウ この問題は、スライディングウィンドウ(尺取り法)と、各文字の出現回数を記録するハッシュ配列を組み合わせることで効率的に解けます。おおまかな流れは次のとおりです。 事前チェック:
-
PythonでN未満の切り詰め可能素数(Truncatable Prime)の合計を求める方法
整数 N が与えられたとき、N 未満に存在するすべての切り詰め可能素数(Truncatable Prime)の合計を求める問題を考えてみましょう。 切り詰め可能素数とは? 切り詰め可能素数とは、次の2つの性質をどちらも満たす数のことです。 左切り詰め可能素数:先頭(左)の桁を1つずつ取り除いていったとき、現れるすべての数が素数である 右切り詰め可能素数:末尾(右)の桁を1つずつ取り除いていったとき、現れるすべての数が素数である たとえば 9137 を見てみましょう。先頭の桁を順に取り除くと 9137 → 137 → 37 → 7 となり、これらはすべて素数です。このように桁を削っても素数
-
Pythonで配列のすべての部分集合から得られる最大差の合計を効率的に求める方法
問題の概要要素が重複してもよい n 個の値を持つ配列 A が与えられたとします。このとき、与えられた配列から作れるすべての部分集合について、その部分集合内の最大値と最小値の差(max(s) − min(s))を求め、それらの合計を計算するのが目的です。ここで、max(s) は部分集合 s 内の最大値、min(s) は最小値を表します。要素が1つだけの部分集合では最大値と最小値が一致するため、差は 0 になります。具体例入力が A = [1, 3, 4] の場合を考えてみましょう。[1]、[3]、[4] → 差はそれぞれ 0[1, 3] → 3 − 1 = 2[1, 4] → 4 − 1 = 3
-
Pythonでソート済み3つの配列から選ぶ三つ組の(max − min)を最小化するアルゴリズム
問題概要サイズが異なっていても構わない、3つのソート済み配列 A、B、C が与えられているとします。このとき、それぞれの配列から1要素ずつ選んだ三つ組 (A[i], B[j], C[k]) について、「三つ組の中の最大値 − 最小値」の絶対差を求め、その最小値を計算するのが目的です。例として、入力が次のような場合を考えてみましょう。A : [2, 5, 6, 9, 11]B : [7, 10, 16]C : [3, 4, 7, 7]このとき出力は 1 になります。A[i] = 6、B[j] = 7、C[k] = 7 を選べば、max(A[i], B[j], C[k]) − min(A[i],
-
Pythonで配列を等しい合計のサブ配列に分割できる合計値を見つける方法
整数の配列Aが与えられたとき、ある値sum[i]ごとに、配列を合計がsum[i]となる複数のサブ配列に分割できるような、すべての合計値を見つける必要があります。もし配列を等しい合計のサブ配列に分割できない場合は、-1を返します。 例えば、入力が A = [2, 4, 2, 2, 2, 4, 2, 6] の場合、出力は [6, 8, 12] になります。これは、配列を合計が6、8、12となるサブ配列にそれぞれ分割できるためです。具体的な分割例は以下の通りです。 合計6の場合: {2, 4}, {2, 2, 2}, {4, 2}, {6} 合計8の場合: {2, 4, 2}, {2, 2, 4}
-
Pythonで3D図形の表面積を求める方法【アルゴリズム解説付き】
問題の概要 N×M の行列 A が与えられ、これは3D図形を表しています。点 (i, j) における柱の高さは A[i][j] であり、この図形全体の表面積を求めるのが目的です。 たとえば、入力が N = 3、M = 3、A = [[1, 4, 5], [3, 3, 4], [1, 3, 5]] の場合、出力は 72 となります。 解法のアプローチ この問題は、各セルと隣接セルの「高さの差」に注目することで効率的に解けます。表面積は大きく分けて2つの要素で構成されます。 上面と底面: グリッドの各マスには必ず上面と底面が存在するため、合計で N × M × 2 となります。 側面: 隣接す
-
Pythonで指定した時刻の後に来る最も近い回文時刻を見つける方法
問題概要24時間形式(HH:MM)で時刻を表す文字列 s が与えられます。HH(時)は 0〜23、MM(分)は 0〜59 の範囲に収まります。このとき、文字列として読んだときに回文(前から読んでも後ろから読んでも同じになる文字列)となる、s より後のもっとも近い時刻を求めてください。該当する時刻が存在しない場合は -1 を返します。たとえば、入力が「22:22」であれば、出力は「23:32」となります。解法のアプローチこの問題は、次の手順に従って解くことができます。n := 文字列 s の長さhour_string := s の先頭2文字(インデックス 0〜2)を切り出した部分文字列minut
-
Pythonでボードを正方形に分割する最小コストを求めるアルゴリズム
問題の概要縦 p、横 q のサイズを持つ1枚のボードがあるとします。このボードを p×q 個の正方形に切り分けるとき、切断にかかる総コストをできるだけ小さくしたいと考えます。それぞれの切断線には個別のコストが設定されており、その値があらかじめ与えられています。例として、横方向の切断コストが X_slice = [3,2,4,2,5]、縦方向の切断コストが Y_slice = [5,2,3] の場合を考えてみましょう。この場合、出力される最小コストは 65 となります。解法のアプローチ(貪欲法)この問題は貪欲法(Greedy Algorithm)を使って効率的に解くことができます。ポイントとなる
-
Pythonで配列内の要素のペアワイズ差を追加し続け、ゲームの勝者を見つける方法
問題概要正の整数のみで構成され、要素がすべて重複のない配列Aがあるとします。ここで、2人のプレイヤーPとQがこの配列を使ってゲームを行います。各手番では、どちらか一方のプレイヤーが配列から2つの数値aとbを選び、絶対差 |a – b| がまだ配列に存在しなければ、その値を新たに配列へ追加します。新しい数を追加できなくなったプレイヤーが負けとなります。プレイヤーPが常に先攻であるとき、このゲームの勝者が誰になるかを求めるのが課題です。たとえば、入力が A = [8,9,10] の場合、出力は「P」になります。解法のアプローチこの問題の鍵を握るのは最大公約数(GCD)です。配列内の任意の2つの数の
-
Pythonでチェス盤を2つに分割せずに入れられるカットの最大数を求める方法
ここでは、A × B のサイズのチェス盤(マトリクス)が与えられたとき、盤面が2つに分割されてしまわないように入れられるカットの最大数を計算する方法を解説します。 例として、A = 2、B = 4 のケースを考えてみましょう。 この場合の出力は 3 となります。 解き方のアプローチ この問題は、次の手順で解くことができます。 結果を格納する変数 res を 0 で初期化します。 res に (M − 1) × (N − 1) を代入します。 res を返します。 この式のポイントは、盤を2つに分割してしまわないためには、盤の端から端まで貫通する完全な切断は行えないという点です。そのため、