-
PythonでK個の要素を削除した後に残る一意な整数の最小数を求める方法
問題の概要整数のみが格納された配列 nums と、削除する個数 k が与えられたとします。このとき、ちょうど k 個の要素を削除した後に残る「一意な(ユニークな)整数」の種類数を最小化することを考えます。例として、nums = [5,4,2,2,4,4,3]、k = 3 の場合を見てみましょう。まず 5 と 3 を削除し、さらに 2 または 4 のどちらか一方を1つ削除すると、残るのは 2 と 4 のみになります。したがって、この場合の出力は 2 となります。解法のアプローチこの問題は貪欲法(グリーディ法)で効率よく解けます。ポイントは、「出現回数が最も少ない要素から順に削除する」ということで
-
Pythonでm個の花束を作るのに必要な最小日数を求めるアルゴリズム(二分探索)
問題概要 整数型の配列 bloomDay と、2つの値 m、k が与えられます。庭には n 本の異なる花があり、i 番目の花は bloomDay[i] 日目に開花します。1つの花束を作るには、隣り合う k 本の花が必要で、各花は1つの花束にしか使用できません。 このとき、m 個の花束を作るために待つ必要のある最小日数を求めてください。もし m 個の花束を作ることが不可能な場合は -1 を返します。 入力例と動作の確認 たとえば、入力が bloomDay = [5,5,5,5,10,5,5]、m = 2、k = 3 の場合、出力は 10 になります。これは、2個(m = 2)の花束を作る必要が
-
Pythonで重複するディレクトリ名を一意にするプログラムの実装方法
問題概要n個の文字列からなる配列 names が与えられたとします。ファイルシステム上にn個のディレクトリを作成し、i番目の時点で names[i] という名前のディレクトリを作成していきます。同じ名前のファイルは存在できないため、重複するディレクトリ名を登録しようとした場合、システムは自動的に「(k)」という形式の接尾辞を追加します。ここで k は、その名前が一意になるような最小の正の整数です。求めるのは長さnの文字列配列であり、ans[i] は i 番目のディレクトリを作成した際に実際に割り当てられる名前になります。例えば、入力が names = [my_dir,my_dir(1),my_
-
Pythonでnのk番目の約数を求めるプログラムの作成方法
正の整数 n と k が与えられたとします。n のすべての約数を昇順に並べたリストを考え、その中から k 番目の約数を求めます。もし約数の個数が k 個未満であれば、-1 を返します。 たとえば、入力が n = 28、k = 4 のとき、出力は 7 になります。28 の約数は [1, 2, 4, 7, 14, 28] であり、その 4 番目が 7 だからです。 解法のアプローチ この問題は、次の手順で解くことができます。 k が 1 の場合は、最小の約数が必ず 1 であるため、1 を返します。 cand を「1」のみを含むリストとして初期化します。 i を 2 から ⌊√n⌋ まで順に調べ、
-
Pythonで1つの要素を削除した後に現れる「1」のみの最長部分配列を求めるアルゴリズム
問題の概要0と1だけで構成されるバイナリ配列 nums が与えられます。この配列から要素を1つだけ削除できるとき、削除後の配列内に存在する「1のみを含む最長の空でない部分配列(サブアレイ)」の長さを求めます。該当する部分配列が存在しない場合は 0 を返します。例えば、入力が nums = [1,0,1,1,1,0,1,1,0] の場合を考えてみましょう。位置5(0始まりのインデックス)にある 0 を削除すると、[1,1,1,1,1] という「1が5個連続した部分配列」が得られるため、出力は 5 となります。解法の考え方この問題は、連続する1の「かたまり(ラン)」ごとに数え直すことで効率的に解け
-
Pythonで配列のペアの合計がkで割り切れるかどうかを確認するプログラム
問題概要 偶数個の要素を含む配列 nums と整数 k が与えられたとします。この配列をちょうど n/2 組のペアに分割し、それぞれのペアの合計が k で割り切れるようにできるかを判定するのが課題です。条件を満たす組み合わせが存在すれば True を、そうでなければ False を返します。 たとえば、nums = [9,5,3,4,7,10,20,8]、k = 3 の場合を考えてみましょう。(9, 3)、(5, 7)、(4, 20)、(8, 10) というペアを作ることができ、すべてのペアの合計が3で割り切れるため、出力は True になります。 解決手順 この問題は、各要素を「kで割った
-
Pythonで最小値と最大値の和がk以下となる部分列の個数を求めるプログラム
問題の概要配列 nums と整数 k が与えられたとき、nums の空でない部分列のうち、「部分列内の最小要素と最大要素の和が k 以下」という条件を満たすものの個数を求めます。答えは非常に大きな値になる可能性があるため、109 + 7 で割った余りを返します。入力例nums = [4, 6, 7, 8]、k = 11 の場合、出力は 4 になります。条件を満たす部分列は次の通りです。[4] … 最小値 4、最大値 4 → 4 + 4 ≤ 11[4, 6] … 最小値 4、最大値 6 → 4 + 6 ≤ 11[4, 6, 7] … 最小値 4、最大値 7 → 4 + 7 ≤ 11[4, 7]
-
Pythonで1のみからなる正方形の部分行列の数を数える方法(動的計画法)
問題の概要m × n の2値(バイナリ)行列が与えられたとき、すべての要素が 1 である正方形の部分行列がいくつ存在するかを求めます。例として、次のような入力を考えてみましょう。011111110111この場合、出力は 15 になります。内訳は以下のとおりです。1辺が1の正方形:10個1辺が2の正方形:4個1辺が3の正方形:1個合計:10 + 4 + 1 = 15解法のアプローチ(動的計画法)この問題は、動的計画法(DP)を使うことで効率的に解けます。各セルについて「そのセルを右下とする最大の正方形の一辺の長さ」を記録していくのがポイントです。手順は以下のとおりです。行列が [[1]] のみの
-
Pythonで全ての要素が1の部分行列を数えるプログラム(DP活用)
m × n のバイナリ行列(各要素が 0 または 1 の行列)が与えられたとき、「すべての要素が 1」で構成される部分行列がいくつあるかを求める問題を考えます。 例として、次のような 3 × 3 の行列を入力してみましょう。 101011011 この場合の出力は 13 になります。内訳は次の通りです。 1 × 1 の部分行列:6 個 2 × 1 の部分行列:3 個 1 × 2 の部分行列:2 個 3 × 1 の部分行列:1 個 2 × 2 の部分行列:1 個 解き方のアプローチ この問題は、動的計画法(DP)の考え方を使うことで効率よく解けます。手順は以下の通りです。 m := 行列の行
-
Pythonでソート済み部分配列の合計から指定範囲の合計を求めるプログラム
問題の概要正の整数を n 個含む配列 nums があるとします。nums のすべての空でない連続する部分配列について合計値を計算し、それらを昇順(非減少順)に並べ替えると、n*(n+1)/2 個の数値からなる新しい配列が得られます。この新しい配列の中から、left 番目から right 番目まで(1始まり・両端を含む)の要素の合計を求めるのが目的です。答えは非常に大きな値になる可能性があるため、結果は 10^9 + 7 で割った余りを返します。入力例たとえば、nums = [1,5,2,6]、left = 1、right = 5 という入力を考えてみましょう。すべての部分配列の合計は「1, 5
-
Pythonで解く「3回の操作後の最大値と最小値の最小差」を求めるアルゴリズム
配列 nums が与えられ、1回の操作で配列内の任意の1つの要素を好きな値に変更できるものとします。このとき、最大3回の操作を行った後の nums の最大値と最小値の差として考えられる最小値を求めるのがこの問題です。 例えば、nums = [3,7,2,12,16] の場合、出力は 1 になります。ソートすると [2,3,7,12,16] となり、大きい方から3つの要素(7, 12, 16)を2〜3の間の値に変更すれば、配列は例えば [2,3,2,2,2] のようになります。このとき最大値は3、最小値は2なので、差は1です。 解法のアプローチ この問題は次の手順で解くことができます。 配列の
-
Pythonで「1」のみを含む部分文字列の個数を求めるプログラム
問題の概要2進数文字列 s が与えられたとき、すべての文字が「1」である部分文字列の個数を求めます。答えは非常に大きな値になる可能性があるため、10^9 + 7 で割った余りを返す必要があります。例えば、入力が s = 1011010 の場合、出力は 5 になります。これは、単独の「1」が4回、「11」が1回現れるためです。解法のアプローチこの問題は、次の手順に従って解くことができます。m := 10^9 + 7 としますresult := 0 で初期化します2進数文字列を「0」で分割します分割された各要素 x に対して、以下を処理しますx が空文字列の場合は、次の反復へ進みますresult
-
Pythonで最大の成功確率を持つパスを見つけるプログラムの実装方法
問題の概要 n 個のノード(ノードには 0 から順に番号が振られています)からなる無向重み付きグラフを考えます。このグラフは辺リスト(edge list)として入力され、各辺 e には「その辺を通過する際の成功確率」probability[e] が割り当てられています。さらに、開始ノード(start)と終了ノード(end)も与えられます。 求めたいのは、start から end へ移動するときに成功確率が最大となる経路であり、答えとしてその成功確率を返します。経路がひとつも存在しない場合は 0 を返してください。 たとえば、次のような入力が与えられたとします。 この場合の出力は 0.25
-
Pythonで同じラベルを持つサブツリー内のノード数を求めるプログラム
ここでは、n個のノードからなる根付きの一般木を考えます。ノードには0からn-1までの番号が振られており、各ノードには小文字の英字ラベルが割り当てられています。ラベルは配列labelsとして与えられ(labels[i]がi番目のノードのラベル)、木は辺リストで表現されます。各辺eは[u, v]という形式で、uが親、vが子であることを意味します。 求めたいのは、サイズnの配列Aです。A[i]には「i番目のノードと同じラベルを持つ、そのサブツリー内のノードの総数」を格納します。 例えば、入力が次のような場合を考えてみましょう。 n = 5、label = ccaca のとき、出力は [3, 2,
-
Pythonで合計が奇数になる部分配列の個数を効率的に求める方法
配列 arr が与えられます。ここで、要素の合計が奇数となる部分配列(サブ配列)の個数を求めます。答えが非常に大きくなる可能性があるため、結果は 109+7 で割った余りとして返します。 例えば、入力が arr = [8,3,7] の場合、出力は 3 になります。すべての部分配列は [8]、[3]、[7]、[8,3]、[3,7]、[8,3,7] の6つであり、それぞれの合計値は 8、3、7、11、10、18 です。このうち奇数となっているのは 3、7、11 の3つであるためです。 解法のアプローチ:累積和の偶奇に着目する すべての部分配列を素朴に列挙すると計算量が O(n²) 以上になり、大き
-
Pythonで文字列の「良い分割」の数を求めるプログラム
ある文字列 s が与えられているとします。s を2つの空でない文字列 p と q に分割し、その連結が元の s と一致し、さらに p と q のそれぞれに含まれる異なる文字の種類数が等しいとき、この分割を「良い分割(good split)」と呼びます。この記事では、s に対して作れる良い分割の数を求める方法を解説します。問題の例たとえば、入力が s = xxzxyx の場合、出力は 2 になります。分割の仕方は複数ありますが、(xxz, xyx) や (xxzx, yx) のように分割したときだけ、両側の異なる文字数が一致するため「良い分割」となります。解決のアプローチこの問題は、文字列を左か
-
Pythonでバイナリ文字列を使った電球スイッチ問題を解くプログラム
問題の概要部屋にn個の電球があり、0からn-1までの番号が振られています。これらの電球は左から右へ一列に並べられており、初期状態ではすべて消灯しています(0の状態)。ここで、与えられたターゲット配列「t」で表される状態を作り出すことが目標です。t[i]は、i番目の電球が点灯していれば「1」、消灯していれば「0」を意味します。電球の状態を切り替えるスイッチが1つあり、反転操作は次のように定義されます。任意の電球のインデックスiを選択する。インデックスiからn-1(右端)までのすべての電球の状態を反転させる。このとき、ターゲットの状態を実現するために必要な最小の反転回数を求めます。例えば、入力が
-
Pythonで二分木の「良い」葉ノードペアの数を求めるプログラム
問題の概要 二分木と整数値 d が与えられます。異なる2つの葉ノードからなるペアのうち、両ノード間の最短経路の長さが d 以下であるものを「良いペア(good pair)」と呼びます。この記事では、Pythonを使って木の中に良いペアがいくつ存在するかを求める方法を解説します。 たとえば、次のような二分木を考えてみましょう。 この木に対して d = 4 とした場合、答えは 2 になります。(8, 7) と (5, 6) の2つのペアは経路長がどちらも 2 で d 以下だからです。一方、(7, 5) や (8, 6) などのペアは経路長が 5 になり、d = 4 を超えるため良いペアとして数
-
【Python】配列ゲームの勝者を見つけるプログラムの実装方法
問題の概要 一意な要素のみを含む配列「arr」と、整数値「k」が与えられているとします。ここで、次のようなゲームを考えてみましょう。 各ターンでは、配列の先頭2つの要素 arr[0] と arr[1] を比較します。大きい方の値が勝者となって位置0に残り、負けた小さい方の値は配列の末尾へ移動します。このゲームは、いずれかの値が k回連続 で勝利した時点で終了し、その時点での勝者が答えとなります。私たちの課題は、この配列から勝者を見つけることです。 具体例 例えば、入力が arr = [1,5,6,3,4,2]、k = 3 の場合、出力は 6 になります。その過程は以下の通りです。 第1ラウ
-
Pythonで二値グリッドを整列させるための最小スワップ回数を求めるプログラム
問題の概要n × n の二値(0と1のみ)行列を考えます。この行列に対して、「隣接する2つの行を選んで入れ替える」という操作を1ステップとして実行できます。ここで求めたいのは、行列の主対角線より上側にあるすべての要素が 0 になるようにするために必要な最小スワップ回数です。どのように行を入れ替えても条件を満たせない場合は、-1 を返します。たとえば、次のような入力が与えられたとします。010011100この場合、出力は 2 になります。2回の隣接スワップで行を並べ替えれば、主対角線より上の要素をすべて 0 にできるからです。解き方のポイントこの問題を効率よく解く鍵は、各行を「右端にいくつ 0