-
Pythonで文字列の相異なる部分列の数を数えるプログラム
文字列 s が与えられたとき、その文字列から作ることができる相異なる部分列(サブシーケンス)の総数を求める問題です。答えが非常に大きくなる可能性があるため、結果は 109 + 7 で割った余りとして返します。 たとえば、入力が s = "bab" の場合、出力は 6 になります。これは "a"、"b"、"ba"、"ab"、"bb"、"bab" の 6 つの異なる部分列が存在するためです。 解法のアプローチ この問題は動的計画法(DP)を用いて効率的に解くこ
-
Pythonですべてのジョブを完了させる最小時間を見つけるプログラム
問題の概要 jobs という配列があり、jobs[i] は i 番目のジョブを完了するために必要な時間を表します。さらに、ジョブを割り当てられる作業者の数 k が与えられます。各ジョブは必ずちょうど1人の作業者に割り当てなければなりません。ある作業者の「作業時間」とは、その作業者に割り当てられたすべてのジョブを完了するのにかかる合計時間のことです。このとき、あらゆる割り当て方の中で最大の作業時間が最小になる値を求めます。 例えば、入力が jobs = [2,1,3,8,5]、k = 2 の場合、出力は 10 になります。次のようにジョブを割り当てられるからです。 作業者1:2 + 5 + 3
-
Pythonでスタンプ操作により目標文字列を作る手順(インデックス配列)を求めるプログラム
小文字だけで構成された目標の文字列(ターゲット文字列)を作りたいとします。最初の時点では、長さ n の「?」(はてなマーク)だけが並んだシーケンスを持っており、これとは別に小文字からなる「スタンプ」が与えられます。各ターンでは、このスタンプをシーケンス上に重ねて押すことができ、重なった部分の文字がスタンプの対応する文字で置き換わります。使用できるターン数は最大でも 10 × n 回です。 例として、初期シーケンスが ?????、スタンプが abc の場合を考えてみましょう。最初のターンで作れる文字列は abc??、?abc?、??abc のいずれかです。スタンプ操作によってターゲット文字列が作
-
Pythonで石の山を1つにまとめる最小コストを求めるプログラム(区間DP)
問題の概要 一列に並んだ N 個の石の山があり、i 番目の山には stones[i] 個の石が入っています。1回の操作では「連続する K 個の山」を1つの山にまとめることができ、そのときのコストは K 個の山に含まれる石の総数に等しくなります。すべての山を1つにまとめる際の最小コストを求めてください。ただし、まとめ方が存在しない場合は -1 を返します。 具体例 nums = [3, 2, 4, 1]、K = 2 の場合、出力は 20 になります。 初期状態:[3, 2, 4, 1] [3, 2] をマージ(コスト 5)→ [5, 4, 1] [4, 1] をマージ(コスト 5)→ [5,
-
Pythonで文字列を3つの回文に分割できるか判定するプログラム
文字列 s が与えられたとき、その文字列を3つの回文(palindrome)の部分文字列に分割できるかどうかを判定する問題を考えてみましょう。 たとえば、入力が s = levelpopracecar の場合、「level」「pop」「racecar」の3つに分割でき、これらはすべて回文であるため、出力は True になります。 解法のアプローチ この問題は、動的計画法(DP)を用いて各部分文字列が回文かどうかを事前に計算しておくことで、効率的に解くことができます。手順は以下の通りです。 n := 文字列 s の長さ dp := n × n の行列を作成し、すべて False で初期化する
-
PythonでK人の労働者を雇うための最小コストを求めるプログラム
問題の概要 労働者ごとの能力値を格納した配列 quality と、それぞれの最低賃金の期待値を格納した配列 wage、そして雇用したい人数 K が与えられます。i 番目の労働者の能力値は quality[i]、最低賃金の期待値は wage[i] です。 K 人の労働者で賃金グループを結成する際には、次の2つのルールを守る必要があります。 グループ内の各労働者への支払額は、グループ内の他のメンバーと比較した能力値(quality)の比率に応じて決まること。 グループ内のすべての労働者が、少なくとも自分の最低賃金の期待値以上を受け取れること。 これらの条件を満たす賃金グループを結成するために必
-
Pythonで解く:全ての友人同士が会話できるようにするための最小の教育人数を求めるアルゴリズム
ここでは、整数 n、配列 languages、配列 friendships が与えられているとします。n 個の言語には 1 から n までの番号が付いており、languages[i] は i 番目のユーザーが習得している言語の集合を表します。また、friendships[i] はペア [ui, vi] として、ユーザー ui と vi の間の友人関係を表します。私たちの目的は、1つの言語を選んで一部のユーザーに教えることで、すべての友人同士が互いにコミュニケーションを取れるようにすることです。そのために教える必要のあるユーザーの最小人数を求めましょう。なお、友人関係は推移的ではない点に注意が必
-
PythonでXORエンコードされた配列から元の順列を復元するプログラム
長さ n(奇数)の配列 perm があり、これは最初の n 個の正整数を並べ替えた順列であるとします。この配列は、enc[i] = perm[i] XOR perm[i+1] という規則によって、長さ n-1 の配列 enc にエンコードされています。本記事では、エンコード後の配列 enc から元の配列 perm を復元する方法を解説します。 例として、入力が enc = [2,5,6,3] の場合、出力は [7, 5, 0, 6, 5] になります。実際に確認すると、隣接要素同士のXORは [7 XOR 5, 5 XOR 0, 0 XOR 6, 6 XOR 5] = [2, 5, 6, 3]
-
Pythonで3つの条件のいずれかを満たすために変更する文字数を最小化するプログラム
問題の概要小文字アルファベットのみで構成された2つの文字列 s と t が与えられます。1回の操作では、s または t 内の任意の1文字を、任意の小文字に変更することができます。目標は、以下の3つの条件のうちいずれか1つを満たすことです。s 内のすべての文字が、t 内のすべての文字よりもアルファベット順で厳密に小さい。t 内のすべての文字が、s 内のすべての文字よりもアルファベット順で厳密に小さい。s と t の両方が、それぞれ1種類の同一文字のみで構成されている。この状態を達成するために必要な最小操作回数を求めます。入力例と考え方例えば、入力が s = sts、t = uss の場合、出力は
-
Pythonでk番目に大きいXOR座標値を求めるプログラムの解説
問題の概要 m × n の行列と整数 k が与えられたとします。このとき、座標 (a, b) の値は、0 ≤ i ≤ a かつ 0 ≤ j ≤ b を満たすすべての要素 matrix[i][j] の XOR 値として定義されます。私たちの課題は、行列内の全座標の値の中からk 番目に大きい値(1始まりのインデックス)を見つけることです。 具体例 たとえば、次のような 2 × 2 の行列を考えてみましょう。 5216 k = 1 の場合、答えは 7 になります。座標 (0, 1) の値は 5 XOR 2 = 7 と計算され、これが全座標の中で最大の値だからです。 解法のアプローチ この問題は、「二
-
Pythonで二分木の2つのノード間の距離を求めるプログラム
二分木が与えられたとき、その中の2つのノード間の距離を求めることを考えます。グラフの場合と同じように、2つのノードを結ぶ経路上の辺(エッジ)の数を数え、その本数を距離として返します。 二分木のノード構造 木の各ノードは、次のような構造を持っています。 data : <整数値> right : <木の別のノードへのポインタ> left : <木の別のノードへのポインタ> 問題の例 例として、次のような二分木を考えてみましょう。 この木において、ノード「2」とノード「8」の間の距離を求めたいとします。このときの出力は 4 になります。 ノード2からノード8へ至
-
Pythonで隣接ペアから元の配列を復元するアルゴリズムを解説
問題の概要サイズ n-1 の2次元配列 adPair が与えられているとします。各 adPair[i] は2つの要素 [ui, vi] を持ち、これは配列 nums において ui と vi が隣接していることを表しています。nums には n 個のユニークな要素が含まれており、この隣接情報だけをもとに元の配列 nums を復元するのが目標です。解が複数存在する場合は、そのうちのどれか1つを返せば構いません。例えば、入力が adPair = [[3,2],[4,5],[4,3]] の場合、出力は [2, 3, 4, 5] となります。解決のアプローチこの問題はグラフの考え方を使うと分かりやすく
-
Pythonで1回の二乗操作後に最大部分配列の合計を求めるプログラム
整数値を含む配列が与えられているとします。この配列に対して、「array[i] の値をその二乗(array[i] × array[i])に置き換える」という操作を1回だけ行うことができます。操作後に得られる最大の部分配列(サブアレイ)の合計を返す必要があります。なお、部分配列は空であってはなりません。 例えば、入力が array = [4, 1, -2, -1] の場合、出力は 17 になります。 array[0] の値を二乗に置き換えると、配列は [16, 1, -2, -1] となります。このとき最大の合計を持つ部分配列は [16, 1] であり、その合計は 16 + 1 = 17 です。
-
Pythonで最後に使用した要素を末尾へ移動するキューを設計するプログラム
整数 1 から n までの値で初期化されたキューを設計することを考えます。このキューには、引数で指定された位置にある要素を取り出し、キューの末尾へ移動する関数を実装します。この関数は何度も呼び出されることを想定しており、呼び出しごとに移動処理を実行したうえで、その時点でキューの末尾にある値を返します。 たとえば、n = 5 でキューを初期化すると、キューには 1 から 5 までの値が格納されます。ここで移動対象の位置として 5、2、3、1 がこの順で与えられた場合、出力は 5、2、4、1 になります。 解決のための手順 この問題は、リストをおよそ √n 個ずつのブロックに分割して管理する「平
-
Pythonで「良い眺め」を持つ建物を見つけるプログラム
高さの異なる建物の高さを格納した配列が与えられているとします。建物は一列に並んでおり、ある建物が「良い眺め」を持つのは、それより高い別の建物によって視界が遮られない場合です。つまり、高さの配列が与えられたとき、他の高い建物に邪魔されずに眺めを楽しめる建物を見つけ出す必要があります。そして、その条件を満たす要素のインデックスを返します。 問題の例 例えば、入力が height = [5, 6, 8, 7] の場合、出力は [2, 3] となります。インデックス0と1の建物は、インデックス2にあるより高い建物に遮られています。一方、インデックス2と3の建物は遮られていません。これは、位置2にある高
-
Pythonで出現回数に基づいてフレーズを分類・並べ替えるプログラム
問題の概要 2つのリストが与えられているとします。1つは選び抜かれたフレーズを格納する「phrases」、もう1つは複数の文を格納する「sentences」です。sentences の各文には、phrases 内のフレーズが含まれることもあれば、含まれないこともあります。 目的は、phrases の各フレーズが sentences 内に何回出現するかを調べ、その出現回数に基づいて phrases を並べ替えることです。そして、並べ替え後のリスト「phrases」を出力として返します。 入力例と出力例 たとえば、入力が次のようになっているとします。 phrases = [strong, du
-
Pythonで最小の長さ差となる等しい部分文字列ペアの個数を求める方法
問題の概要 小文字アルファベットのみで構成された2つの文字列が与えられます。このとき、次の条件をすべて満たす四つ組 (p, q, r, s) の個数を求めることを考えます。 0 <= p <= q <= 1つ目の文字列の長さ 0 <= r <= s <= 2つ目の文字列の長さ 1つ目の文字列のインデックス p〜q にある部分文字列と、2つ目の文字列のインデックス r〜s にある部分文字列が完全に一致する 上記の条件を満たすすべての四つ組の中で、q − r の値が最小である たとえば、firstString = hgfn、secondString = gf
-
Pythonで受け入れられる招待状の数を求めるプログラム ― DFSによる二部グラフマッチング
パーティーの準備で、m人の男子とn人の女子がいるとします(m = n)。各男子は必ず女子を一人連れて参加しなければならず、男子たちは全員が女子に招待状を送ります。ただし、各女子が受け入れられる招待状は一通だけです。このとき、女子が実際に受け入れられる招待状の総数を求めます。 入力はm × nの行列として与えられ、セル(i, j)は「男子iが女子jに招待状を送ったかどうか」を表します。値が1なら招待状を送ったこと、0なら送っていないことを意味します。 入力例 100101110 この場合の出力は3になります。 女子1が男子1の招待状を受け入れる 女子2が男子3の招待状を受け入れる 女子3が男子
-
【Python】コインで作れる連続値の最大数を求めるプログラム
n個の要素を持つ配列 coins があり、これは私たちが所有しているコインを表しています。i番目のコインの価値は coins[i] で示されます。n枚のコインの中からいくつかを選び、その価値の合計がxになるようにできるとき、「値xを作ることができる」と定義します。このとき、0から始まる連続した値について、コインで作ることができる最大の連続値の個数を求めるのが本記事の目的です。 問題の例 たとえば、入力が coins = [1,1,3,4] の場合、出力は 10 になります。これは次のように、0から9までのすべての値を作れるためです。 0 = [] 1 = [1] 2 = [1,1] 3 =
-
Pythonで配列を互いに素な左右の部分配列に分割する方法を解説
問題の概要 配列 nums が与えられたとき、これを「left」と「right」という2つの部分配列に分割します。この分割は、以下の条件を満たす必要があります。 left 内のすべての要素が、right 内のどの要素以下であること left と right がどちらも空でないこと left のサイズが可能な限り小さいこと そして、このような分割を行った後の left の長さを求めます。 具体例 たとえば、入力が nums = [5,0,3,8,6] の場合、出力は 3 になります。これは、left 配列が [5,0,3]、right 部分配列が [8,6] に分割されるためです。 解法のア