-
Pythonで二分木の対角線ごとの要素の合計を求める方法
問題の概要 二分木が与えられたとき、木の各対角線(右上から左下に向かう経路)ごとに、その対角線上のノード値の合計を求めることを考えます。 たとえば、次のような二分木が入力だったとします。 この場合、対角線は [12, 15]、[8, 10]、[3] の3本になるため、それぞれの合計を求めると出力は [27, 18, 3] となります。 アルゴリズム この問題を解くには、次の手順に従います。まず traverse() 関数を定義します。この関数は node、numLeft、output の3つの引数を受け取ります。 node が null(None)の場合は、そのまま return します
-
Pythonでn個のサイコロの出目の合計がtotalになる組み合わせの数を求めるプログラム
本記事では、サイコロの個数 n、各サイコロの面の数 faces、そして目標となる合計値 total が与えられたとき、n 個のサイコロを振った結果の合計が total と一致する組み合わせが何通りあるかを求める問題を解説します。答えが非常に大きな数になる可能性があるため、結果は 109 + 7 で割った余りとして返します。 例えば、入力が n = 2、faces = 6、total = 8 の場合、出力は 5 になります。これは、2つの6面ダイスで合計8を作る方法が次の5通り存在するためです。 (2 と 6) (6 と 2) (3 と 5) (5 と 3) (4 と 4) 解法のアプロー
-
Pythonでグラフの頂点間の到達可能性行列を計算するプログラム
隣接リスト形式で表現されたグラフが与えられたとき、次のような条件を満たす2次元行列Mを求めることを考えます。M[i, j] = 1:頂点iから頂点jへの経路(パス)が存在する場合M[i, j] = 0:経路が存在しない場合例えば、次のようなグラフが入力として与えられたとします。この場合の出力は、以下の5×5の行列になります。1111101111011110111101111解法のアプローチこの問題は、各頂点を起点とした幅優先探索(BFS)を用いることで効率的に解くことができます。具体的な手順は以下の通りです。n×nの2次元行列「ans」を作成し、すべての要素を0で初期化します(nは頂点の総数)
-
Pythonで文字列の文字を使って作れる一意な回文の数を数えるプログラム
文字列 s が与えられたとき、その文字列に含まれるすべての文字を使って作成できる一意な回文の数を求めます。答えが非常に大きくなる可能性があるため、結果は 109 + 7 で割った余りを返します。 例えば、入力が s = xyzzy の場合、出力は 2 になります。「zyxyz」と「yzxzy」という2種類の回文を作ることができるためです。 解法の考え方 回文は左右対称の構造を持っています。つまり、文字列の左半分の並び方が決まれば、右半分は自動的に決まります。この性質を利用して、以下の手順で問題を解きます。 m = 10^9 + 7:剰余を取るための値を設定します。 char_freq:文字列
-
Pythonで二分木の各ノードを左右の部分木の合計値で更新するプログラム
問題の概要 二分木が与えられたとき、各ノードの値を「自分自身の値 + 左右の部分木の合計」に置き換えた木を求めることを考えます。つまり、木を葉から根へ(ポストオーダー)たどりながら、すべてのノードを部分木の総和で更新していく処理です。 例えば、次のような二分木が入力として与えられたとします。 この場合、出力は次のようになります。 アルゴリズム この問題は再帰を使ったポストオーダー走査でシンプルに解けます。手順は以下の通りです。 関数 tree_sum() を定義します。引数として木のルートを受け取ります。 ルートが None(空)の場合は 0 を返します。 そうでなければ、ルートの値を
-
Pythonでリストの全要素を等しくするための最小総コストを求めるプログラム
nums と costs という2つの数値リストがあると仮定しましょう。ここで、nums[i] の値を costs[i] のコストで増加または減少させるという操作を考えます。この操作は何度でも実行でき、nums のすべての要素を同じ値に揃えたいとします。このとき、必要となる最小の総コストを求めるのが課題です。たとえば、入力が nums = [3, 2, 4]、costs = [1, 10, 2] の場合、出力は 5 になります。これは、3 を 2 に減らすのにコスト 1 がかかり、さらに 4 を 2 回減らすのにそれぞれコスト 2 ずつ(合計 4)かかるためです。解決のアプローチこの問題を解く
-
Pythonで整数のすべての素因数をソート順に求めるプログラム
1より大きい整数 n が与えられたとき、その数のすべての素因数を見つけ、昇順(ソートされた順序)で返すことを考えます。任意の整数は素数の積として表すことができ、これらの素数がその数の素因数となります。なお、同じ素因数が複数回現れる場合もあります(例:12 = 2 × 2 × 3)。例えば、入力が 42 の場合、出力は [2, 3, 7] となります。解法のアプローチこの問題は「試し割り法」と呼ばれる手法で解くことができます。手順は以下の通りです。結果を格納する新しいリスト res を用意するn が 2 で割り切れる間、以下を繰り返すres の末尾に 2 を追加するn := n ÷ 2 の商とす
-
Pythonでリストにピタゴラス数(三つ組)が存在するかチェックする方法
問題概要nums という数値のリストが与えられたとき、次の等式を満たす3つの数 a、b、c が存在するかどうかを判定します。a² + b² = c²これはいわゆる「ピタゴラス数(三つ組)」の有無を確認する問題です。例えば、入力が [10, 2, 8, 5, 6] の場合、8² + 6² = 64 + 36 = 100 = 10² が成り立つため、出力は True になります。解法のアプローチこの問題は、全ての組み合わせを総当たりで調べることも可能ですが、降順ソート+二ポインタ法を使うことでより効率的に解けます。全体の手順は以下の通りです。nums 内のすべての数値を2乗し、降順にソートしたリス
-
Pythonで2つの長方形が重なっているかどうかを判定するプログラム
長方形を4つの要素を持つリスト [x1, y1, x2, y2] で表すことを考えます。ここで、(x1, y1) は左下の角の座標、(x2, y2) は右上の角の座標を表します。2つの長方形が「重なっている(オーバーラップしている)」とは、それらの共通部分(交差領域)の面積が正の値になる場合を指します。つまり、角や辺だけが接している2つの長方形は、重なっているとはみなしません。問題例例えば、入力が R1 = [0,0,2,2]、R2 = [1,1,3,3] の場合、2つの長方形は面積を持つ共通領域を持つため、出力は True になります。一方、R1 = [0,0,1,1]、R2 = [1,1,
-
Pythonで文字列内の最初の繰り返し文字のインデックスを検索する方法
文字列 s が与えられたとき、その中で最初に繰り返し出現する文字のインデックスを求める問題を考えてみましょう。繰り返し文字がひとつも存在しない場合は、-1 を返します。 例えば、入力が "abcade" の場合、出力は 3 になります。これは、文字 a がインデックス 3 の位置に再び現れているためです。 解法のアプローチ この問題を解くには、以下の手順に従います。 文字の出現履歴を記録するための辞書(マップ)chars を定義します。 i を 0 から文字列の長さまで順にループさせます。 s[i] がすでに chars に存在する場合、その時点のインデックス i を
-
Pythonで再帰的インデックス参照を用いて要素の集合のサイズを求めるプログラム
問題の概要数字のリスト A と別の数値 k が与えられたとします。このとき、{A[k], A[A[k]], A[A[A[k]]], ...} のような新しい集合を作成します。インデックスが範囲外になる直前まで処理を続けます。最終的に、この集合のサイズを求めます。ただし、途中で循環(サイクル)が発生した場合は -1 を返します。たとえば、入力が A = [1,2,3,4,5,6,7]、k = 1 である場合、A[1] = 2、A[2] = 3、A[3] = 4、A[4] = 5、A[5] = 6、A[6] = 7 となるため、集合は {2,3,4,5,6,7} となり、そのサイズは 6 です。解
-
【Python】リスト内の重複要素を見つけて最後の出現箇所だけを削除する方法
数値のリストが与えられたとき、その中から重複している数値をすべて見つけ出し、最後に出現した箇所のみを削除するプログラムを考えます。 例えば、入力が [10, 30, 40, 10, 30, 50] の場合、10 と 30 がそれぞれ2回ずつ出現しています。これらの最後の出現箇所を取り除くと、出力は [10, 30, 40, 50] になります。 解決のための手順 この問題は、以下の手順に従って解くことができます。 seen := 新しい辞書(マップ)を作成する d := 新しい辞書(マップ)を作成する i を 0 から nums のサイズまで繰り返す: nums[i] が d に存在しない
-
【Python】1文字を削除して別の文字列に変換できるか判定する方法
2つの文字列 s と t が与えられたとき、s から1文字だけ削除することで t と同じ文字列を作れるかどうかを判定する問題について解説します。問題の例たとえば、入力が以下の場合を考えてみましょう。s = worldt = wrldこの場合、world から「o」を1文字削除すると wrld になるため、出力は True となります。解決のアプローチこの問題は、次の手順で解くことができます。インデックス i を 0 で初期化し、文字列 s の長さを n として取得します。i が n 未満である間、以下を繰り返します。s の i 番目の文字を取り除いた文字列(前半部分と後半部分を連結)を tem
-
Pythonで各桁の合計を1桁になるまで繰り返し計算する方法【デジタルルート】
正の整数 n が与えられたとき、そのすべての桁の数字を足し合わせて新しい数を作り、この操作を結果が10未満(1桁)になるまで繰り返すことを考えます。このようにして得られる「1桁に還元された数」はデジタルルート(数根)と呼ばれる有名な概念です。 例えば、入力が 9625 の場合、出力は 4 になります。計算の流れは以下のとおりです。 9 + 6 + 2 + 5 = 22 2 + 2 = 4 解法のアプローチ この問題は、再帰呼び出しを利用すると簡潔に解くことができます。具体的な手順は次のとおりです。 solve() メソッドを定義し、引数として n を受け取る n < 10 の場合、
-
Pythonで文字列内に複数回出現する長さkの部分文字列の個数をカウントする方法
文字列 s と整数 k が与えられたとき、s の中に2回以上出現する長さ k の部分文字列がいくつあるかを求める問題を考えてみましょう。 たとえば、入力が s = xxxyyy、k = 2 の場合、出力は 2 になります。これは「xx」と「yy」という2つの部分文字列が、それぞれ複数回出現しているためです。 解決のアプローチ この問題は、以下の手順で解くことができます。 seen := 空のリストを用意する i を 0 から (s の長さ - k) まで繰り返す: t := s のインデックス i から i + k - 1 までの部分文字列 t を seen の末尾に追加する mp :
-
Pythonで文字列が同じパターンの繰り返しかどうかを判定する方法
ある文字列が与えられたとき、それが繰り返し文字列(同じ部分文字列が2回以上連なって全体を構成している文字列)であるかどうかを判定する問題を考えてみましょう。 例えば、入力が helloworldhelloworld の場合、「helloworld」が2回繰り返された文字列なので、出力は True となります。 解法のアプローチ:約数に注目する この問題を効率よく解くカギは約数です。文字列の長さを n とするとき、繰り返しの単位となる部分文字列の長さ i は必ず n の約数になります。つまり、n の約数だけを候補として調べれば十分だということです。 具体的な手順は以下の通りです。 n を文字
-
Pythonでリストの部分リストを反転させて別のリストと一致させられるか判定するプログラム
問題概要2つの数値リスト A と B が与えられたとします。リスト A 内の任意の部分リスト(サブリスト)を選んで反転することができ、この操作は何度でも繰り返せます。このとき、A を B と同じ並びに変換できるかどうかを判定するのが目的です。例えば、入力が A = [2, 3, 4, 9, 10]、B = [4, 3, 2, 10, 9] の場合、[2, 3, 4] と [9, 10] の2つの部分リストをそれぞれ反転するだけでよいので、出力は True になります。解き方のポイント実は、「部分リストの反転を何度でも行える」という条件があるため、隣接する2要素だけを反転することも可能です。これ
-
Pythonで文字列内の各単語の順序を逆にするプログラムの書き方
スペースで区切られた複数の単語からなる文字列が与えられたとき、その単語の並び順を逆にする方法を解説します。例えば、入力が「Hello world, I love python programming」だった場合、出力は「programming python love I world, Hello」のようになります。解決の手順この問題は、以下のステップで解決できます。まず、文字列 s を空白文字で分割し、単語のリスト temp を作成します次に、リスト temp の要素の順序を逆にします最後に、temp の要素を空白区切りで連結した文字列を返しますそれでは、実際のコード実装を見ていきましょう。コ
-
Pythonで目標金額に達するまでの年数を計算するプログラムの作り方
問題の概要 パラメータとして、元本P、交互に適用される2つの利率OとE、そして目標金額Tが与えられます。Pドルを株式市場に投資し、市場は毎年交互にE%とO%の利回りを返すものとします。このとき、資産額が少なくともTドルに達するまでに何年かかるかを求めるのが課題です。 たとえば、入力が P = 200、O = 10、E = 25、T = 300 の場合、出力は 3 になります。1年目に25%の利息が付いて 200 + 50 = 250 ドルとなり、2年目に10%が付いて 250 + 25 = 275 ドル、3年目に再び25%が付いて 275 × 1.25 = 343.75 ドルになります。これ
-
Pythonで左端または右端の位置に到達できるかどうかを確認するプログラム
問題の概要R、B、ドット(.) の3種類の文字を含む文字列を考えてみましょう。R は現在位置、B は移動が妨げられている(ブロックされた)位置、ドット(.) は空いている位置を表します。1ステップごとに、現在位置から有効な(空いている)隣接する位置へ移動することができます。このとき、文字列の左端または右端の位置に到達できるかどうかを判定する必要があります。例えば、入力が s = ...........R.....BBBB..... の場合、出力は True になります。これは、R の左側にブロック(B)がひとつも存在しないため、R は左端の位置に到達できるからです。解決のアプローチこの問題を解