-
Pythonで2つの場所にある金塊を回収する最小コストを求めるプログラム
問題の概要2次元の行列(グリッド)と、開始位置・目標位置を表す複数の値(row、col、erow0、ecol0、erow1、ecol1)が与えられます。現在位置は matrix[row][col] であり、matrix[erow0][ecol0] と matrix[erow1][ecol1] の2箇所に置かれた金塊を回収したいとします。移動は上下左右の4方向が可能ですが、セル (r, c) に立ち入るときにはコスト matrix[r][c] を支払う必要があります。ただし、同じセルに何度足を踏み入れても、そのセルのコストは最初の1回しか支払いません。この条件下で、2つの金塊をどちらも回収すると
-
Pythonで同一直線上にある点の最大数を求めるプログラム
問題の概要 座標のリストが与えられているとします。各座標は x と y の2つの値から構成され、デカルト平面(直交座標系)上の1点を表しています。ここで求めたいのは、「ある1本の直線上に同時に乗っている点の最大数」です。 たとえば、入力が [[6, 2],[8, 3],[10, 4],[1, 1],[2, 2],[6, 6],[7, 7]] の場合、出力は 4 になります。これは [1, 1]・[2, 2]・[6, 6]・[7, 7] の4点が、直線 y = x 上にきれいに並んでいるためです。 考え方:傾きごとに点をグループ化する この問題は「傾き」に着目すると効率よく解けます。ある基準点
-
Pythonで木の特定の辺を含む一意なパスの総数をカウントするプログラム
木構造を表す辺のリスト (u, v) が与えられます。ここで、各辺について「その辺を含む一意なパス(単純パス)」の総数を求め、入力された辺と同じ順序で結果を返す必要があります。例として、入力が edges = [[0, 1], [0, 2], [1, 3], [1, 4]] の場合を考えてみましょう。この場合、出力は [6, 4, 4, 4] となります。解き方のアプローチこの問題は、以下の手順で解くことができます。与えられた辺から隣接リスト adj を作成します。各頂点の部分木サイズを記録するためのマップ count を用意します。関数 dfs(x, parent) を定義します。count
-
Pythonで正規表現パターンと文字列の一致を判定するプログラムの書き方
文字列 s と正規表現パターン p が与えられたとき、そのパターンが文字列全体と一致するかどうかを判定する問題を考えてみましょう。ここで扱う正規表現は、次の2つの特殊文字のみをサポートするシンプルなルールに基づいています。 . (ピリオド): 任意の1文字に一致します。 * (アスタリスク): 直前の要素の0回以上の繰り返しに一致します。 たとえば、pattern = h.l*o、s = hello という入力の場合、「.」が「e」に一致し、「l*」が「ll」(0回以上の l の繰り返し)に一致するため、出力は True になります。 解法のアプローチ:再帰によるマッチング この問題は
-
PythonでS式(S式記法)の文字列を評価して結果を求める方法
文字列 s がS式(S-expression)として与えられたとき、そのS式を評価し、結果を整数として返すことを考えます。 S式とは、単一の数値、あるいは括弧で囲まれた再帰的な式のことです。例えば (+ (- 3 2) (* 3 3)) は (3 - 2) + (3 * 3) を意味し、その計算結果は 10 になります。使用できる演算子は +、-、*、/ の4種類です。 例えば、入力が s = (- (+ 3 2) 2) の場合、((3 + 2) - 2) = 3 となるため、出力は 3 になります。 解決のアプローチ S式は前置記法(ポーランド記法)で書かれているため、右側から順に読み込んで
-
Pythonで2つの島を結ぶ最短の橋の長さを求めるプログラム(DFS+BFS解説)
問題の概要0を水、1を陸地とするバイナリ行列が与えられます。「島」とは、上下左右の4方向で連結している「1」の集合のことであり、各島は周囲を水(0)または行列の端に囲まれています。この問題では、2つの島を結ぶ最短の橋の長さを求めます。例えば、次のような入力が与えられた場合を考えてみましょう。001101100この場合の出力は 1 となります。点 (1,0) と点 (1,2) を結ぶ橋を1つ架ければ、2つの島がつながるためです。解法のアプローチこの問題は、次の2段階の手法で効率的に解くことができます。DFS(深さ優先探索)を使って、最初に見つかった島全体のセルを記録する。BFS(幅優先探索)を使
-
Pythonで2つの文字列を含む最短スーパーシーケンス(共通超系列)の長さを求めるプログラム
2つの文字列 s と t が与えられたとき、s と t の両方を部分列として含む最短の文字列(最短共通スーパーシーケンス)の長さを求める問題を考えてみましょう。例えば、入力が s = pipe、t = people の場合、答えは 7 になります。これは「pieople」という文字列が、両方の文字列を部分列として含む最短の例の一つだからです。解法の考え方:LCS(最長共通部分列)を利用するこの問題は動的計画法(DP)を使って効率的に解けます。ポイントとなるのは次の関係式です。最短スーパーシーケンスの長さ = len(s) + len(t) − LCS(s, t)つまり、まず2つの文字列の最長共
-
Pythonで水に完全に囲まれた島をすべて削除するプログラムの実装方法
問題の概要0と1だけで構成される二値行列を考えます。ここで1は陸地、0は水を表します。「島」とは、1が上下左右(斜めは含まない)に連なったグループのことです。この問題では、行列の外周(端)に一切接しておらず、水に完全に囲まれている島を見つけ出し、それらをすべて0(水)に変換します。言い換えれば、「行列の端にたどり着ける陸地だけを残し、内部に孤立した島をすべて消す」ことが目的です。入力例10000110011001100001出力例10000000000000000001中央にあった大きな島は外周に接していないためすべて0になり、一方で外周に接している四隅の陸地はそのまま残ります。解法のアプロー
-
Pythonで合計がターゲット以上になる最短の部分リストのサイズを求めるプログラム
問題の概要 数値のリスト nums と整数 target が与えられます。このとき、要素の合計が target 以上となる最短の連続する部分リストのサイズを求めてください。条件を満たす部分リストが存在しない場合は -1 を返します。 たとえば、nums = [2, 11, -4, 17, 4]、target = 19 が入力された場合、出力は 2 になります。[17, 4] を選べば合計は 21 となり、19 以上という条件を満たすからです。 解法の考え方:累積和と単調キュー この問題は、累積和(prefix sum)と単調キュー(monotonic deque)を組み合わせることで、O(n
-
Pythonで安全な距離を保てる最大のkの値を求めるプログラム
0と1だけで構成された2次元のバイナリ行列を考えてみましょう。ここで「0」は空きセル(誰もいないマス)、「1」は人が存在するセルを表します。2つのセル間の距離は、x座標の差とy座標の差のうち大きい方の値(チェビシェフ距離)として定義されます。ある空きセルから、行列内のすべての人、および行列の4つの辺それぞれへの距離がすべてk以上であるとき、この行列は安全係数kにおいて「安全」であるとみなされます。この記事では、安全性を保証できる最大の係数kの値を求める方法を解説します。 たとえば、入力が以下のような行列だったとしましょう。 0000001010011100111000000 この場合、出力は
-
Pythonで隣接する木の高さがすべて異なるようにするための最小コストを求めるプログラム
問題の概要 植物の高さを表す整数リスト heights と、各植物の高さを1つ増やすのに必要なコストを表すリスト costs が与えられます。隣り合う植物どうしの高さがすべて異なるようにするために必要な最小コストを求めるのが目的です。 たとえば、heights = [3, 2, 2]、costs = [2, 5, 3] という入力の場合、出力は 3 になります。最後の植物の高さを1だけ増やせば(コスト3)、リストは [3, 2, 3] となり、隣接する高さがすべて異なる状態になるからです。 解き方のアプローチ(動的計画法) この問題は動的計画法(DP)を使うと効率的に解けます。ポイントは、各
-
Pythonでn(t)形式の文字列を展開・デコードするプログラムの実装方法
問題の概要 ある文字列 s が与えられ、これはより長い元の文字列をエンコードしたものだとします。n(t) という表記は「文字列 t を n 回繰り返して連結したもの」を意味し、t には通常の文字列だけでなく、別のエンコード済み文字列が再帰的に含まれることもあります。この記事では、エンコードされた文字列 s をデコード(展開)するPythonプログラムを紹介します。 たとえば、入力が s = 3(pi)2(3(am))0(f)1(u) の場合、出力は pipipiamamamamamamu になります。「pi」が3回、「am」が6回(2×3)、「f」は0回のため無視され、「u」が1回繰り返された
-
Pythonで「最小値×サイズ」の積が最大になる部分リストを見つけるプログラム
問題概要 数値のリスト nums と整数 pos が与えられます。このとき、インデックス pos を必ず含むような連続する部分リスト A を選び、「A の最小値 × A の要素数」が最大になるようにした場合の値を返すプログラムを作成します。 例として、入力が nums = [-2, 2, 5, 4]、pos = 3 の場合を考えてみましょう。このとき最適な部分リストは [5, 4] です。最小値は 4、要素数は 2 なので、答えは 4 × 2 = 8 となります。 解法のアプローチ この問題は貪欲法(グリーディ法)を使うことで効率的に解けます。基本的な考え方は次のとおりです。 まず、pos
-
Pythonプログラム:1要素を削除した後、最大値と最小値を同時に含む部分リストの数を求める方法
問題の概要数値のリスト nums が与えられ、リストから最大1つの要素を削除できるとします。このとき、削除後のリストにおける「最大値と最小値の両方を含む部分リスト(サブリスト)」の数の最大値を求めるのが目的です。入力例たとえば、入力が次の場合を考えてみましょう。nums = [3, 2, 6, 2, 4, 10]この場合、出力は 8 になります。理由は、要素 10 を削除するとリストは [3, 2, 6, 2, 4] となり、最大値と最小値(この場合は最大値6、最小値2)を両方含む部分リストが以下の8個存在するためです。[2, 6][6, 2][2, 6, 2][3, 2, 6][6, 2,
-
Pythonで数値リストのすべての部分列の幅の合計を効率的に求めるプログラム
数値のリスト nums が与えられたとします。ここで、ある数列の「幅」とは、その数列に含まれる最大値と最小値の差として定義します。このとき、nums のすべての部分列(サブシーケンス)の幅を求め、それらの合計を計算します。結果が非常に大きな数になる場合は、109+7 で割った余りを返してください。 例えば、入力が nums = [7, 4, 9] の場合、出力は 15 になります。考えられる部分列は [7]、[4]、[9]、[7, 4]、[7, 9]、[4, 9]、[7, 4, 9] の7つで、それぞれの幅は 0、0、0、3、2、5、5 となるため、その合計は 15 になるからです。 解法の
-
Pythonでk×k部分行列の最小値を求めるプログラム【スライディングウィンドウ法】
問題の概要2次元の行列と整数 k が与えられたとき、すべての k × k 部分行列に含まれる最小値を要素とする新しい行列を返すプログラムを考えます。たとえば、次のような入力が与えられたとします。3568654312ここで k = 2 とした場合、出力は [[3, 5], [3, 3]] になります。この結果は、各2×2の部分行列ごとの最小値を表しています。具体的には次の通りです。左上の部分行列:最小値は 33 5 8 6右上の部分行列:最小値は 55 6 6 5左下の部分行列:最小値は 38 6 4 3右下の部分行列:最小値は 36 5 3 12解き方のアプローチこの問題は、スライディングウィ
-
Pythonでエッジが最小全域木(MST)に含まれるかどうかを判定するプログラム
問題概要無向グラフを表す2次元配列 edges が与えられているとします。配列の各要素は1本のエッジを表し、(u, v, w) という形式を持ちます。これは「ノード u と v が接続されており、そのエッジの重みが w である」ことを意味します。さらに、整数 a と b が与えられ、これらはエッジ (a, b) を指します。求めたいのは、エッジ (a, b) が最小全域木(MST: Minimum Spanning Tree)の一部になり得るかどうかの判定です。前提条件: グラフは連結であり、エッジ (a, b) は必ずグラフ内に存在するものとします。入力例[[0, 2, 100], [1,
-
Pythonで単語リストがしりとりの輪(円環)になるか判定するプログラム
問題の概要 単語のリストが与えられたとき、それらの単語をすべて1回ずつ使って「しりとりの輪(円環)」を作れるかどうかを判定する問題です。単語Aを単語Bの直前に連結できるのは、Aの末尾の文字とBの先頭の文字が一致する場合のみです。なお、最初と最後の単語の接続は考慮しません。 例えば、次のような入力を考えてみましょう。 words = [ant, dog, tamarind, nausea, gun] この場合、以下のように単語を並べると輪になります。 ant → tamarind(t → t) tamarind → dog(d → d) dog → gun(g → g) gun → nause
-
Pythonで木構造内の特別なノードを見つけるプログラム
ここでは、「tree」という2次元リスト(n分木を表す)と、「color」という値のリストが与えられているとします。木は隣接リスト形式で表現されており、その根(ルート)は tree[0] です。ノードの特徴i番目のノードは以下の特徴を持ちます。tree[i]:そのノードの子ノードと親ノードの情報color[i]:そのノードの色「特別なノード」とはあるノードNを根とする部分木に含まれるすべてのノードの色が一意(重複なし)である場合、そのノードNを「特別(special)」なノードと呼びます。この定義に基づき、与えられた木の中に特別なノードがいくつあるかを求めるのが本問題の目的です。入力例tree
-
Pythonでグリッド内に作れる正方形の数を数えるプログラム
問題概要等間隔に点が配置された、p行×q列のグリッドがあるとします。このグリッド上の点を頂点として作れる「一意な正方形」の総数を求めるのが本記事のテーマです。答えが非常に大きな値になる可能性があるため、結果は 109 + 7 で割った余りとして返します。ここでいう正方形とは、4つの点を頂点とし、4辺の長さがすべて等しい図形のことです。重要なのは、正方形は必ずしもグリッドの軸に平行である必要がないという点です。つまり、傾いた正方形も有効な解としてカウントします。例えば、入力が p = 4、q = 4 の場合、出力は 20 になります。解き方のアプローチこの問題は、各正方形を「外接する正方形領域」