-
【Python】増加部分と減少部分がそれぞれ異なる2つの配列からなる最長ビトニックシーケンスを求める方法
2つの配列が与えられたとき、次の条件を満たす最長のビトニックシーケンス(バイトニック配列)を求める問題を考えてみましょう。「増加する部分」は1つ目の配列の部分列であり、「減少する部分」は2つ目の配列の部分列である必要があります。たとえば、入力が A = [2, 6, 3, 5, 4, 6]、B = [9, 7, 5, 8, 4, 3] である場合、出力は [2, 3, 4, 6, 9, 7, 5, 4, 3] となります。解法のアプローチこの問題は、最長増加部分列(LIS: Longest Increasing Subsequence)を求めるアルゴリズムを応用することで効率的に解けます。基本
-
Pythonで文字の削除・並べ替えにより生成できる最長回文を求めるアルゴリズム
問題の概要 ある文字列が与えられたとき、そこから文字を削除または並べ替え(シャッフル)することで作成できる最長の回文を見つけることを考えます。候補となる回文が複数存在する場合は、そのうちの1つを返せば十分です。 例えば、入力が pqqprrs の場合、出力は pqrsrqp になります。 解き方の考え方 回文とは、前から読んでも後ろから読んでも同じになる文字列のことです。回文を構成するには、各文字が中心を基準に左右対称にペアで配置されている必要があり、最大で1文字だけ中央に単独で置くことができます。 この性質を利用すると、以下の手順で最長回文を構築できます。 サイズ256の配列 count
-
Pythonで重複する配列から欠落要素を見つける方法【二分探索で効率化】
問題の概要互いに重複関係にある2つの配列が与えられますが、そのうち片方の配列には1つだけ要素が欠けています。この欠落している要素を見つけるのが本記事の課題です。例えば、入力が A = [2, 5, 6, 8, 10]、B = [5, 6, 8, 10] の場合、2番目の配列には「2」が含まれていないため、出力は 2 となります。解決のアプローチこの問題は、二分探索(バイナリサーチ)を活用することで、O(log N) の時間計算量で効率的に解くことができます。なお、この手法は両方の配列が昇順にソートされていることを前提としています。手順は以下の通りです。solve() 関数を定義します。引数とし
-
Pythonで左右の最も近い小さい要素間の最大差を求める方法
問題の概要整数の配列が与えられたとき、各要素について「左側で最も近い小さい要素」と「右側で最も近い小さい要素」の絶対差を計算し、その最大値を求める問題です。ある要素の左側または右側により小さい要素が存在しない場合は、0 をその小さい要素として扱います。例えば、入力が A = [3, 5, 9, 8, 8, 10, 4] の場合、出力は 4 になります。これは次のように計算されます。左側の最も近い小さい要素 L = [0, 3, 5, 5, 5, 8, 3]右側の最も近い小さい要素 R = [0, 4, 8, 4, 4, 4, 0]最大絶対差 |L[i] − R[i]| = |8 − 4| =
-
Pythonで都市と最寄り駅の間の最大距離を求めるアルゴリズム
問題概要N個の都市があり、それぞれ0からN-1までの番号が付けられているとします。さらに、駅が設置されている都市のリストも与えられます。このとき、任意の都市からその最寄りの駅までの距離の最大値を求めるのが目的です。なお、駅のある都市は任意の順序で与えられる可能性がある点に注意してください。たとえば、入力が N = 6、stations = [2, 4] の場合、出力は 2 になります。解法のアプローチこの問題は、以下の手順で解くことができます。まず、サイズNのブール型リスト station_present を作成し、すべてFalseで初期化します。stationsに含まれる各都市について、st
-
Pythonで最大長のスネークシーケンスを見つける方法
スネークシーケンスとは数値が格納された2次元グリッド(マトリックス)が与えられたとき、その中からスネークシーケンスを見つけて返す問題を考えてみましょう。候補が複数存在する場合は、どれか1つを返せば十分です。スネークシーケンスとは、グリッド内の隣接するセルの数値をつなげて作る列のことです。各セルにおいて、右隣または下隣のセルの値は、現在のセルの値に対して ±1 でなければなりません。つまり、現在位置がセル (a, b) にある場合、右隣のセル (a, b+1) の値が ±1 なら右へ移動でき、下隣のセル (a+1, b) の値が ±1 なら下へ移動できます。例として使うグリッド107639876
-
Pythonで「最初のN個の自然数の2乗和がX以下」となる最大のNを二分探索で求める方法
整数 X が与えられたとき、「最初の N 個の自然数の2乗の合計が X を超えない」ような最大の N を求める問題を考えてみましょう。 例えば、X = 7 の場合を考えます。N = 3 とすると、1² + 2² + 3² = 1 + 4 + 9 = 14 となり、X = 7 を超えてしまいます。一方、N = 2 なら 1² + 2² = 5 であり、X 以下に収まります。したがって、答えは 2 となります。 解法のアプローチ この問題は、次の手順で二分探索(バイナリサーチ)を使うことで効率的に解くことができます。 まず、2乗和を計算する関数 sum_of_squares() を定義します。引
-
PythonでN=(P!/Q!)を1に減らす最大操作回数を求める方法
問題の概要 2つの整数 P と Q が与えられ、これらから N = P!/Q! という数が作られます。この N を、実行可能な限り多くの操作回数で 1 まで減らすことを考えます。ここでいう1回の操作とは、「N がある整数 X で割り切れるとき、N を N/X に置き換える」というものです。目的は、この操作を行える最大回数を求めることです。 具体例 入力が A = 7、B = 4 の場合を考えてみましょう。このとき N = 7!/4! = 5 × 6 × 7 = 210 となります。 210 を 1 にするには、素因数ごとに順番に割っていくのが最適です。210 = 2 × 3 × 5 × 7
-
Pythonで配列の要素を削除して得られる最大ポイントを求める方法
問題の概要 N個の要素を持つ配列 A と、2つの整数 l・r が与えられます(要素の値は 1 ≤ ax ≤ 10^5、かつ 1 ≤ l ≤ r ≤ N を満たします)。配列から任意の要素 ax を1つ取り除くと、それと同時に「ax+1、ax+2、…、ax+R」および「ax−1、ax−2、…、ax−L」に等しい値をもつすべての要素も配列から削除されます。この操作を行うと ax ポイントを獲得できます。配列のすべての要素を削除し終えたとき、獲得できる合計ポイントの最大値を求めるのが目的です。 たとえば、入力が A = [2,4,3,10,5]、l = 1、r = 2 の場合、出力は 18 になり
-
Pythonでi < j < kかつa[i] < a[j] < a[k]を満たすトリプルの最大合計を求める方法
問題の概要正の数からなる配列が与えられ、その配列には n 個の要素が含まれているとします。このとき、0 <= i < j < k < n かつ a[i] < a[j] < a[k] という条件を満たすトリプル (a[i] + a[j] + a[k]) の合計の最大値を求める必要があります。例として、入力が A = [3, 6, 4, 2, 5, 10] の場合を考えてみましょう。このとき、条件を満たすトリプルとその合計は以下のようになります。(3, 4, 5): 合計 = 12(3, 6, 10): 合計 = 19(3, 4, 10): 合計 = 17(4,
-
Pythonで二分探索木(BST)の中央値をO(n)時間・O(1)空間で求める方法
問題の概要 二分探索木(Binary Search Tree、BST)が与えられたとき、その中央値を求めることを考えます。ノードの総数を n とすると、中央値は次のように定義されます。 n が奇数の場合: 中央値 = 中序順(昇順)で (n+1)/2 番目のノードの値 n が偶数の場合: 中央値 = (n/2 番目のノードの値 + (n+1)/2 番目のノードの値) / 2 例として、次のようなBSTを考えてみましょう。 7 / \ 4 9 / \ / \ 2 5 8 10 この木の中序走査(昇順)の結
-
Pythonで配列の最小調整コストを求める方法【動的計画法で解説】
問題の概要 正の整数からなる配列が与えられたとします。ここで、配列内の隣接する2つの要素の差が、指定された値 target 以下になるように、各要素を新しい値へ置き換えることを考えます。 このとき、元の値と新しい値の差の絶対値の合計、すなわち調整コストを最小化することが目的です。数式で表すと、次の合計を最小化することになります。 Σ |A[i] − Anew[i]| (i は 0 から n−1 まで) ここで、n は配列 A のサイズ、Anew は隣接要素間の差が target 以下となるように調整した後の配列です。 入出力の例 たとえば、入力が次の場合を考えてみましょう。 [56, 78,
-
Pythonで指定された制約条件下ですべてのジョブを完了する最小時間を求める方法
それぞれ所要時間の異なるジョブの配列があり、これらのジョブを担当する作業者が k 人いるとします。さらに、各作業者がジョブ 1 単位を処理するのにかかる時間 t も与えられています。このとき、次の制約条件下で、すべてのジョブを完了させるために必要な最小時間を求めます。 各作業者に割り当てられるのは連続したジョブのみであること。 複数の作業者が 1 つのジョブを分担して処理することはできないこと。 たとえば、入力が k = 4、t = 5、job = {12, 6, 9, 15, 5, 9} の場合、出力は 75 になります。これは [12]、[6, 9]、[15]、[5, 9] のようにジ
-
Pythonで連続する番号のソート済み配列から欠落した要素を見つける方法
問題の概要 n個の重複しない数値からなる配列Aを考えます。これらの要素は昇順に並んでいますが、そのうち1つだけが欠落しています。この欠落している要素を効率的に見つけ出すのが課題です。 例えば、入力が A = [1, 2, 3, 4, 5, 6, 7, 9] のような場合、出力は 8 となります。 解決の手順(アルゴリズム) 配列がソート済みであるという特性を活かし、二分探索を用いることでこの問題を解決できます。連続した数列では、欠落が発生していない位置のインデックスiに対して「A[i] − i == A[0]」という関係が常に成り立ちます。この性質を利用して、欠落位置を絞り込んでいきます。
-
【Python】ビット単位ORがKと等しくなるN個の異なる数を見つける方法
2つの整数 N と K が与えられたとき、それらのビット単位のOR(論理和)を計算すると結果がちょうど K と等しくなるような、N個の互いに異なる値を見つけることを考えます。条件を満たす組み合わせが存在しない場合は -1 を返します。 たとえば、入力が N = 4、K = 6 の場合、出力は [6, 0, 1, 2] となります。実際に確認すると、6 OR 0 OR 1 OR 2 = 6 となり、条件を満たしていることがわかります。 解法のアプローチ この問題は、次の手順で解くことができます。 MAX := 32 — 扱うビット幅を32ビットとします。 visited: サイズ MAX のリ
-
Pythonで文字列のn番目の辞書式順列を効率的に求める方法
長さmの文字列があり、この文字列が小文字の英字のみで構成されているとします。このとき、辞書順(辞書式順序)で並べたときのn番目の順列を求めたいという問題を考えます。 たとえば、入力が string = pqr、n = 3 だった場合、出力は qpr になります。これは、pqr のすべての順列を辞書順にソートすると [pqr, prq, qpr, qrp, rpq, rqp] となり、3番目が qpr だからです。 解決のためのアプローチ この問題は、以下の手順で解くことができます。 階乗テーブルの作成: MAX_CHAR を 26、MAX_FACT を 20 とし、factorials
-
Pythonで漸化式のn番目の項を求める方法:log₂(bₙ)の計算
次のような数列 bn を考えてみましょう。この数列は、b1 = 1 および bn+1/bn = 2n という漸化式で表されます。ここでの課題は、与えられた n に対して log2(bn) の値を求めることです。たとえば、入力が 6 の場合、出力は 15 になります。これは log2(bn) = (n × (n − 1)) / 2 = (6 × (6 − 1)) / 2 = 15 となるためです。数学的な導出手順この問題は、漸化式を段階的に展開することで解くことができます。bn+1/bn = 2nbn/bn−1 = 2n−1…(中略)…b2/b1 = 21上記の式をすべて掛け合わせると、左辺の分
-
Pythonで全ペアのGCDから元の配列を復元する方法
問題の概要 ある配列Aが与えられたとします。この配列の各要素は、別の配列(元の配列)から選んだ2つの要素のペアごとに計算した最大公約数(GCD)に対応しています。私たちの課題は、このGCD配列をもとに、計算に使用された元の数値を復元することです。 例として、入力が A = [6, 1, 1, 13] の場合を考えてみましょう。このときの出力は [13, 6] となります。理由は以下の通りです。 gcd(13, 13) = 13 gcd(13, 6) = 1 gcd(6, 13) = 1 gcd(6, 6) = 6 アルゴリズムの鍵となる考え方 このアルゴリズムのポイントは、「GCD配列の中
-
Pythonでソート済み双方向連結リストから積が指定値と一致するペアを検索する方法
一意な正の整数で構成されたソート済みの双方向連結リスト(doubly linked list)があるとします。このリストの中から、積が指定された値 x と一致するペアを見つける必要があります。重要なポイントは、余分なメモリ領域を消費せずに解くことです。 例えば、入力が次のような場合を考えてみましょう。 L = 1 ⇔ 2 ⇔ 4 ⇔ 5 ⇔ 6 ⇔ 8 ⇔ 9、x = 8 このとき、出力は (1, 8) と (2, 4) になります。 アルゴリズムの考え方:二ポインタ手法 この問題は、配列の「二ポインタ(two pointer)」テクニックを連結リストに応用することで、O(n) の時間計算量・
-
【Python】合計がNに等しく積が最大となる4つの約数を見つけるプログラム(セット2)
ある数 N が与えられたとき、N のすべての約数を求め、以下の条件を満たす4つの約数の積を返すことを考えます。4つの約数の合計が N と等しいこと4つの約数の積が最大であること積を最大化するため、4つの約数は互いに同じ値でも構わない問題例たとえば入力が N = 60 の場合、出力は次のようになります。すべての約数:1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30, 60最大の積:50625この場合、15 を4回選ぶことで積が最大になります(15 × 15 × 15 × 15 = 50625、かつ 15 × 4 = 60)。解法のアプローチこの問題は、次の手順で解くことが