-
Pythonで連続文字の制限を満たす同サイズの文字列を数えるプログラム
小文字の英字だけで構成された文字列 s と整数 k が与えられます。このとき、次の3つの条件をすべて満たす文字列の総数を求めるのが今回の課題です。 s と同じ長さである 辞書順で s 以下である 同じ文字が連続する回数が k 以下である(k を超える連続は不可) 答えは非常に大きくなる可能性があるため、10^9 + 7 で割った余りとして返します。 たとえば入力が s = app、k = 2 のとき、条件を満たす文字列は 405 個あるため、出力は 405 になります。 解法の考え方:桁DP 「指定した文字列以下の文字列を数え上げる」タイプの問題では、桁DP(デジットDP)と呼ばれる手法が
-
Pythonで全アイテムをちょうど1つずつ購入する最小コストを求めるプログラム
N個のアイテムがあり、それぞれ0、1、2、…、N-1という番号が付けられているとします。ここで、サイズSの2次元リストsetsが与えられます。i番目のセットは価格sets[i][2]で購入することができ、sets[i][0]からsets[i][1]までの範囲にあるすべてのアイテムを受け取れます。さらに、サイズNのリストremovalsも与えられ、i番目の要素のインスタンスを1つ、価格removals[i]で廃棄できます。このとき、0からN-1までの各要素をちょうど1つずつ入手するための最小コストを求めてください。どうしても実現できない場合は-1を返します。入力例sets = [ [0,
-
Pythonの動的計画法でコンテストの期待得点を最大化するプログラム
複数の問題が出題されるプログラミングコンテストを想定します。このコンテストには少し変わったルールがあり、1問でも正解した時点でコンテストは終了します。 同じ長さを持つ2つのリスト points と chances が与えられます。i番目の問題では、chances[i]% の確率で正解して points[i] ポイントを獲得できます。また、挑戦できる問題数の上限を表す値 k が与えられ、同じ問題に2回以上挑戦することはできません。 この問題のゴールは、最適な戦略を取ったときに獲得できるポイントの期待値を求め、最も近い整数に丸めて返すことです。i番目の問題に挑戦することの期待値は points[i
-
Pythonで方程式を成立させるために必要な最小の数字挿入回数を求めるプログラム
文字列 s が与えられ、これは x+y=z の形式で表される方程式を意味するとします。このとき、s に数字を挿入して等式が正しく成立するようにするために必要な、最小の挿入回数を求めるのがこの問題です。例えば、入力が s = 2+6=7 の場合、出力は 2 になります。これは、「1」と「2」を挿入することで方程式を「21+6=27」に書き換えられるためです。つまり、必要な修正回数は合計2回となります。解法のアプローチこの問題は、桁ごとの繰り上がりを考慮した動的計画法(DP)を用いて解くことができます。手順は以下の通りです。文字列 s を「+」記号で分割し、左側を A、右側を rest とします。
-
Pythonで加重グラフの最小コストを求めるプログラムの実装方法
問題の概要整数の2次元リスト edges が与えられます。これは無向グラフを表しており、各行は1本の辺 [u, v, w] に対応します。つまり、ノード u とノード v が接続されており、その辺の重みが w であることを意味します。グラフは 0 から n-1 までの n 個のノードで構成されています。ここで「パスのコスト」は、パスに含まれる辺の数とパス上の辺の重みの最大値の積として定義されます。求めるのは、ノード 0 からノード n-1 へ到達するときの最小コストであり、そのようなパスが存在しない場合は -1 を返します。たとえば、入力が次のようなケースを考えてみましょう。edges = [
-
Pythonでリストの最大パワーを求める:要素を1つ移動して最大化するアルゴリズム
問題の定義リストの「パワー」とは、すべてのインデックス i における (i + 1) × list[i] の総和として定義される値です。数式で表すと次のようになります。$$\displaystyle\sum\limits_{i=0}^{n-1} (i+1)\times list[i]$$ここで、N 個の正の整数からなるリスト nums が与えられます。私たちが行える操作は、リスト内の任意の 1 つの要素を選び、それを別の任意の位置へ移動(入れ替えではなく移動)することだけです。リストの先頭や末尾への移動も許されており、そもそも何も移動しないという選択も可能です。このとき、実現できるリストのパワ
-
Pythonで1からkまでのすべての数で割り切れる最小の整数xの末尾ゼロの個数を求めるプログラム
問題の概要ある数 k が与えられたとき、1 から k までのすべての整数で割り切れる最小の正整数 x を考えます。つまり、x が 1 から k までのすべての数の倍数となるような最小の値です。この x の末尾に連続して並ぶゼロ(後続ゼロ)の個数を求めるのが課題です。例えば、入力が k = 6 の場合を考えてみましょう。このとき条件を満たす最小の x は 60 です。60 は 1、2、3、4、5、6 のすべてで割り切ることができます。そして 60 の末尾にはゼロが 1 個あるため、出力は 1 となります。解決のためのアプローチこの問題は、次の手順で解くことができます。res := 0、x :=
-
Pythonでリストを非増加リストに変換するために必要な最小操作回数を求めるプログラム
問題概要 数値のリスト nums が与えられたとします。使用できる操作は「隣接する2つの値を選び、その合計値を持つ1つの値にマージする」ことだけです。この操作を繰り返してリスト全体を非増加(左から右へ値が増加しない状態)にするとき、必要となる最小の操作回数を求めます。 たとえば、入力が nums = [2, 6, 4, 10, 2] の場合を考えてみましょう。まず先頭の [2, 6] をマージして [8, 4, 10, 2] とし、続けて [8, 4] をマージして [12, 10, 2] とすれば、リストは非増加になります。操作は2回なので、答えは 2 です。 解法の考え方(動的計画法)
-
Pythonで文字列の全部分文字列に含まれる固有文字の数を合計するプログラム
問題概要小文字のみで構成された文字列 s が与えられます。s のすべての部分文字列を対象に、それぞれの部分文字列内で重複せず一度だけ現れる文字の個数を数え、その総和を求めます。答えが非常に大きくなる場合は、10^9 + 7 で割った余りを返します。たとえば、入力が s = xxy のとき、出力は 6 になります。各部分文字列と固有文字のカウントは以下のとおりです。x : 1x : 1y : 1xx : 0(x が重複しているため)xy : 2xxy : 1(x が重複しているため)合計すると 1 + 1 + 1 + 0 + 2 + 1 = 6 となり、これが求める答えです。解法のポイントすべて
-
Pythonで左上と右下のセルを分断するために必要な最小の壁の数を求めるプログラム
2次元のバイナリ行列を考えます。「0」は空きセル、「1」は壁を表します。この問題では、左上のセルから右下のセルへ至る経路が完全に存在しなくなるようにするために、最低何個のセルを壁へ変更すればよいかを求めます。ただし、左上と右下のセルそのものに壁を設置することはできません。また、移動は上下左右の4方向のみが許され、斜め移動はできません。 例として、次のような入力を考えてみましょう。 0000010001100000 この場合の出力は「2」です。たとえば下のように2つのセルを壁に変えることで、左上から右下へのすべての経路を遮断できます。 0100010001100010 解法のアプローチ この問題
-
Pythonで解く!人が火災を避けて左上または右下のセルに到達できるかを判定するプログラム
問題の概要 以下のように、いくつかの異なる値を持つ2次元マトリックス(行列)を想定します。 0:空きセル 1:人 2:火災 3:壁 ここで、マトリックス上には人が1人だけ存在し、毎ターン火災は上下左右の4方向へ広がっていきます。ただし、火災は壁を越えて広がることはできません。私たちの課題は、人がマトリックスの左上隅または右下隅のいずれかに到達できるかどうかを判定することです。 判定の際に押さえておくべきルールは以下の通りです。 各ターンでは、人が先に移動し、その後で火災が広がります。 人が目標セルに到着したのと同じターンで火災がそのセルに広がっても、人は安全です。つまり、人がセルに入っ
-
Pythonで「すべてのxをyより前に配置する」ために必要な最小の反転回数を求めるプログラム
問題概要小文字の文字列 s が与えられ、その文字は x と y のみで構成されているとします。ここで、「1つの x を y に変更する」、またはその逆の「1つの y を x に変更する」という操作を考えます。この操作を繰り返し行い、すべての x がすべての y よりも前に並ぶようにしたい場合、必要な操作の最小回数を求めるのが目的です。たとえば、入力が s = yxyyyyxyxx の場合、出力は 4 になります。解き方の手順この問題は、以下の手順で解くことができます。y_left := 0 で初期化します。x_right := s 内の x の個数、res := s 内の x の個数 とします
-
Pythonで2つの文字列を交互に組み合わせて目的の文字列を形成できるか判定するプログラム
2つの文字列 s と t、そしてもう1つの文字列 r が与えられたとき、s と t の文字をそれぞれの並び順を崩さずに交互に組み合わせることで、r を作れるかどうかを判定する問題を考えます。これは「インターリービング(interleaving)」と呼ばれる典型的な文字列操作の問題です。 たとえば、入力が s = xyz、t = mno、r = xymnoz の場合、出力は True になります。「xymnoz」は「xyz」と「mno」の文字を順番に交互につなぎ合わせることで形成できるからです。 解決のためのアプローチ この問題は再帰関数を使って、以下の手順で解くことができます。 関数 sol
-
Pythonで隣接するペアの合計が完全平方数となる順列の数をカウントするプログラム
数値のリスト nums が与えられたとき、「隣接する任意の2つの値の合計が完全平方数(平方数)となる」ような順列の個数を求める問題を考えてみましょう。2つの順列 A と B は、あるインデックス i において A[i] と B[i] が異なるとき、互いに異なる順列として区別します。 例えば、入力が nums = [2, 9, 7] の場合、出力は 2 になります。これは [2, 7, 9](2+7=9、7+9=16)と [9, 7, 2](9+7=16、7+2=9)の2通りが条件を満たすためです。どちらも隣接要素の和が 9 や 16 といった完全平方数になっていますね。 解法のアプローチ この
-
Pythonで先攻プレイヤーが他のプレイヤーより多くのキャンディーを獲得できるか判定するプログラム
「candies」という数値のリストがあり、2人のプレイヤーがより多くのキャンディーを集める競争をしているとします。このゲームはターン制で行われ、プレイヤー1が先攻です。各ターンで、プレイヤーはリストの先頭または末尾のどちらかからキャンディーを1つ取ることができます。ここでの課題は、プレイヤー1が相手よりも多くのキャンディーを集められるかどうかを判定することです。 問題の例 例えば、入力が candies = [1, 4, 3, 8] の場合、出力は True になります。なぜなら、プレイヤー1は初手で末尾の8個のキャンディーを取ることができ、その後、相手が先頭の1か3のどちらを選んでも、残り
-
Pythonでキャンディーゲームの勝敗を判定!プレイヤー1が最大スコアを獲得できるかチェックする方法
2人のプレイヤーがゲームを行う状況を考えてみましょう。一列に並んだ複数のキャンディーがあり、プレイヤー1には各キャンディーの点数を表す数値リスト nums が与えられます。各プレイヤーのターンでは、列の先頭から1個・2個・3個のいずれかの数だけキャンディーを取り除き、その合計点数を自分のスコアに加算します。すべてのキャンディーがなくなった時点でゲームは終了し、より高いスコアを獲得したプレイヤーが勝者となります。ここでは、プレイヤー1がこのゲームに勝てるかどうかを判定する方法を解説します。 たとえば、入力が nums = [1, 1, 2, 3, 50] の場合、出力は True になります。
-
Pythonで2次元行列から収集できるコインの最大量を求めるプログラム
問題の概要 ここでは、2次元の行列(マトリックス)を扱います。各セル mat[r][c] には、そのマスに置かれたコインの枚数が格納されています。プレイヤーは任意のマスからスタートし、「上・下・左・右」の4方向(斜め移動は不可)に移動しながらコインを集めていきます。 移動したマスのコインはすべて回収され、そのマスの値は 0 に変わります。さらに、コインが 0 枚のマスには立ち入ることができないという制約があります。この条件下で、収集できるコインの合計の最大値を求めるのが本記事の目的です。 これは典型的なグラフ探索の問題であり、一度訪れたマスは二度と使えないため、「重み付きグリッド上の最長経路問
-
Pythonで解くコイン収集問題:左上から右下への往復移動で取得できる最大コイン数を求めるプログラム
問題の概要0、1、-1 の3種類の値を含む2次元マトリックス(グリッド)を考えます。各値の意味は次のとおりです。0:何もない空のセル1:コインが置かれたセル-1:通過できない壁左上のセルを出発点として、「右」または「下」方向への移動のみで右下のセルまで進み、そこから今度は「上」または「左」方向への移動のみで左上のセルへ戻ります。この往復移動で収集できるコインの最大数を求めるのが目的です。コインを取得したセルの値は 0 に変わり、同じコインを二度取得することはできません。また、右下のセルに到達できない場合は 0 を返します。入力例と出力たとえば、次のようなマトリックスが与えられたとします。011
-
Pythonで数値文字列を分割して値のリストを作れるパターン数をカウントするプログラム
問題概要 0〜9の数字のみから構成される文字列 s と、整数 k が与えられます。このとき、s を [1, k] の範囲に含まれる数値からなるリストとして分割できる方法が何通りあるかを求めます。答えが非常に大きくなる可能性があるため、結果は 10^9 + 7 で割った余りを返します。 たとえば、入力が s = "3456"、k = 500 の場合、出力は 7 になります。これは次の7通りの分割が可能であるためです。 [3, 4, 5, 6] [34, 5, 6] [3, 4, 56] [3, 45, 6] [34, 56] [345, 6] [3, 456] 解法の考
-
Pythonで2次元バイナリ行列から異なる島の形状を検出するプログラム
問題の概要2次元のバイナリ行列が与えられ、その中に存在する「異なる島」の数を求めることを考えます。ここで、1 は陸地、0 は水を表します。島とは、上下左右に隣接した 1 の集合であり、その周囲がすべて水に囲まれている領域のことです。そして、2つの島は形状が異なる場合にのみ「一意(ユニーク)」であるとみなされます。たとえば、入力が以下のような行列だったとします。100001010101101001001000011011この場合、出力は 4 になります(異なる島はそれぞれ別の色で表されています)。解法のアプローチこの問題は、深さ優先探索(DFS)を使って各島のセルをすべて訪問し、その形状を「相対