-
Pythonで島(図形)の周囲長を求めるアルゴリズムと実装方法
問題の概要 0が空きセル、1がブロック(図形の一部)を表す2値行列を考えます。このとき、図形の周囲長(外周の長さ)を求めるのが課題です。なお、図形の内部に穴は存在しないものとします。 例えば、次のような入力が与えられた場合を考えてみましょう。 0000000111001100111000000 この場合の出力は 14 になります。 解法のアプローチ 基本的な考え方はシンプルです。各セルは最大で4つの辺を外周に持ちますが、隣接するセルも1である場合、その共有される辺は外周に含まれません。そこで、以下の手順で計算を行います。 d := 0(現在の行インデックス)、perimeter := 0(周
-
Pythonでサイズkの各ウィンドウに含まれる一意な要素の数を求めるプログラム
数値のリスト nums と整数 k が与えられたとき、サイズ k の各ウィンドウ(連続する k 個の要素)に含まれる異なる数値(ユニークな要素)の個数を順番に求める問題です。問題の例たとえば、入力が nums = [2, 2, 3, 3, 4]、k = 2 の場合を考えてみましょう。このとき、各ウィンドウは次のようになります。[2, 2] → 一意な要素数は 1(2のみ)[2, 3] → 一意な要素数は 2(2と3)[3, 3] → 一意な要素数は 1(3のみ)[3, 4] → 一意な要素数は 2(3と4)したがって、出力は [1, 2, 1, 2] となります。解き方のアプローチこの問題は「
-
Pythonでスタックのリストからk個の要素をポップしたときの最大合計を求めるプログラム
複数のスタック(リスト)と整数 k が与えられたとき、各スタックから要素をポップし、合計でちょうど k 個の要素を取り出した場合に得られる最大の合計値を求める問題を考えてみましょう。 例えば、入力が stacks = [[50, -4, -15], [2], [6, 7, 8]]、k = 4 の場合、出力は 39 になります。最初のスタックから3つの要素をすべてポップし、最後のスタックから末尾の要素を1つポップすると、-15 + (-4) + 50 + 8 = 39 という合計が得られるためです。 解法のアプローチ この問題は再帰(バックトラッキング)を用いて解くことができます。重要なポイント
-
Pythonで連結リストの後ろからK番目のノードを見つけるプログラム
問題概要片方向連結リストが与えられたとき、後ろからk番目のノード(0始まりのインデックス)の値を求めることを考えます。ただし、この問題はリストを1回の走査(シングルパス)で解く必要があります。例えば、入力が node = [5,4,6,3,4,7]、k = 2 の場合、出力は 3 になります。これは、後ろから2番目(インデックス3)のノードの値が3であるためです。解法のアプローチ:2ポインタ技法この問題を効率的に解くには、2つのポインタを使う手法が有効です。片方のポインタを先にkステップだけ進めておき、その後両方のポインタを同時に末尾へ向けて進めます。先頭のポインタが末尾に到達したとき、もう片
-
【Python】ソート済みリストからk番目に欠けている数を効率的に求める方法
ソートされた重複のない整数リスト nums と整数 k が与えられたとき、リストの最初の要素を基準にして、k番目(0始まりのインデックス)に相当する欠落した数を見つける問題を考えてみましょう。 問題の例 例えば、nums = [5,6,8,10,11]、k = 1 という入力の場合を確認します。このリストには「7」と「9」という2つの数が欠けています。7がインデックス0(1番目)の欠落数、9がインデックス1(2番目)の欠落数に対応するため、k = 1 のときの出力は 9 となります。 解決のためのアプローチ この問題は、隣り合う要素同士の差に注目することで解けます。各間隔にいくつの数が欠け
-
【Python】二分探索木でk番目に小さい要素を効率的に求めるアルゴリズムと実装例
問題の概要 二分探索木(BST: Binary Search Tree)と整数 k が与えられたとき、木の中で k 番目に小さい値を見つけることを考えます。 例えば、次のような二分探索木があるとします。 5 / \ 4 10 / \ 7 15 / \ 6 8 このとき k = 3 であれば、出力は 7 になります。 アプローチ:スタックを使った中順走査(In-order Traversal) 二分探索木には「中順走査を行うと、ノードを値の昇順に訪問できる」という重要な性質が
-
【Python】文字列を高々K種類の異なる文字にするために必要な最小の変更回数を求めるプログラム
小文字のアルファベットのみで構成された文字列 s と整数 k が与えられたとき、結果として得られる文字列が「高々 k 種類の異なる文字」しか含まないようにするために必要な最小の変更回数を求めます。ここでいう「変更」とは、1文字を別の任意の文字に置き換える操作のことです。たとえば、入力が s = wxxyyzzxx、k = 3 の場合、出力は 1 になります。これは、文字 w を x・y・z のいずれか1文字に置き換えるだけで、異なる文字の種類を3種類(x、y、z)にできるからです。解法のアプローチこの問題は、次の手順で解くことができます。まず、文字列 s 内の各文字の出現頻度をカウントしたマッ
-
Pythonで単語リストから最大のアナグラムグループを見つける方法
問題の概要文字列のリスト words が与えられたとき、互いにアナグラム(並べ替えた文字列)の関係にある単語同士をすべてグループ化し、その中で最も大きなグループのサイズを返すことを考えます。アナグラムとは、同じ文字を構成要素として持ち、文字の順序だけが異なる文字列のことです。たとえば「xyz」「zyx」「yzx」は、それぞれの文字の出現回数が同一であるため、同じアナグラムグループに属します。例として、入力が words = [xy, yx, xyz, zyx, yzx, wwwww] の場合を考えてみましょう。このとき「xy」と「yx」が1つのグループ、「xyz」「zyx」「yzx」が3つの単
-
Pythonで最大値と最小値の差が最小になるサイズkのリストを選ぶ方法
数値のリスト nums と整数 k が与えられたとき、nums から要素を選んでサイズ k のリストを作成し、そのリスト内の最大値と最小値の差をできるだけ小さくすることを考えます。そして、その最小の差を返すのがこの問題の目的です。 例えば、入力が nums = [3, 11, 6, 2, 9]、k = 3 の場合、出力は 4 になります。これは、最適なリストとして [2, 3, 6] を作成でき、最大値 6 と最小値 2 の差が 4 になるためです。 解法のアプローチ この問題を解くには、以下の手順に従います。 リスト nums をソートする 空のリスト ls を用意する i を 0 から
-
Pythonで循環リストの最大部分配列合計を求めるプログラム
数値のリスト nums が与えられたとします。ここで、nums の先頭と末尾が隣り合っている「循環リスト」を考えます。このとき、循環リスト内の空でない部分リスト(部分配列)の中から、合計が最大になるものを見つける必要があります。 例として、入力が nums = [2, 3, -7, 4, 5] の場合を考えてみましょう。この場合の出力は 14 になります。部分リスト [4, 5, 2, 3] を選ぶと、その合計は 14 になるからです。 解法のアプローチ この問題は、有名なKadaneのアルゴリズムを応用することで効率的に解けます。ポイントは、答えとなる部分配列が2通りの場合に分けられることで
-
Pythonで最大の合計を持つ連続サブリスト(部分配列)の合計を求めるプログラム
配列 A が与えられたとき、「最大の合計を持つ連続した部分リスト(サブアレイ)」を見つけ、その合計値を返すことを考えます。例えば、配列が A = [-2, 1, -3, 4, -1, 2, 1, -5, 4] の場合、答えは合計 6 となり、該当する部分配列は [4, -1, 2, 1] です。解き方:動的計画法(DP)の活用この問題は、動的計画法(Dynamic Programming)を使うことで効率的に解けます。基本的な考え方は、「各位置で終わる部分配列の合計の最大値」を順番に求めていくというものです。配列 A と同じサイズの配列 dp を用意し、すべて 0 で初期化するdp[0] :=
-
Pythonでリストの隣接しない要素の最大合計を求めるプログラム
数値のリスト nums が与えられたとき、互いに隣接しない要素だけを選んだ場合の最大合計を返す関数を作ることを考えます。リストには 0 や負の数が含まれている場合もあります。 たとえば、入力が [3, 5, 7, 3, 6] のとき、出力は 16 になります。これは、3・7・6 を選ぶことで要素同士が隣接せず、合計 16 を達成できるためです。 解き方の手順 この問題は動的計画法(DP)の考え方を使うと、O(n) の計算量で効率よく解けます。手順は次のとおりです。 リストの長さが 2 以下の場合は、max(nums) をそのまま返す noTake(現在の要素を選ばない場合の最大合計)を 0
-
Pythonで二分木の任意の2ノード間における最大パス合計を求めるプログラム
二分木の最大パス合計とは二分木が与えられたとき、任意の2つのノードをつなぐパスの中で、ノードの値の合計が最大になるものを求める問題です。ここでいう「パス」とは、木の中で隣接するノード同士を順にたどる経路のことで、必ずしも根(ルート)から始まる必要はありません。例として、次のような二分木を考えてみましょう。この場合、最適なパスは [12, 13, 14, 16, 7] となるため、出力される答えは 62 になります。解法のアプローチこの問題は再帰(深さ優先探索)を使って効率的に解くことができます。各ノードに対して「そのノードを端点とする片側だけの最大合計」と「そのノードを折り返し点とした両側を含
-
Pythonで各行・各列に重複しない数字が入るよう正方形マトリクスを埋められるか判定するプログラム
問題の概要 n × n の行列が与えられ、各セルには 0 から n までの値が入っているものとします。ここで 0 は「未記入のマス」を表します。この課題では、空きマスを適切に埋めて、各行および各列に 1 から n までの数字がそれぞれちょうど1回ずつ現れるようにできるかどうかを判定します。 たとえば、入力が次のような行列だったとしましょう。 002201123 この場合の出力は True になります。実際、次のようにマスを埋めることが可能だからです。 312231123 この種の問題は数独(ナンプレ)によく似ていますが、3×3 のブロック制約がない点が異なります。行と列の制約だけで成立するた
-
Pythonで二分木のすべての葉が同じレベルにあるかどうかを確認するプログラム
二分木が与えられたとき、そのすべての葉(リーフノード)が同じレベル(同じ深さ)に存在するかどうかを判定する問題を考えてみましょう。例えば、次のような二分木が入力として与えられた場合、出力は True になります。解決のアプローチこの問題を解くために、以下の手順に従います。dfs() という関数を定義します。この関数は root(現在のノード)と d(現在の深さ)を受け取ります。root が null でない場合、以下の処理を行います。root の左の子と右の子がどちらも null の場合(つまり葉ノードの場合)、d を depth リストの末尾に追加します。それ以外の場合は、再帰的に探索を続け
-
Pythonで二分木の左端の最深ノードを求めるプログラム
二分木が与えられたとき、最も深い位置にあるノードの値を求めることを考えます。最深ノードが複数存在する場合は、その中で最も左側にあるノードの値を返します。 例えば、次のような二分木が入力された場合を考えてみましょう。 この場合、出力は 4 になります。最も深いレベルには 4 と 7 の2つのノードがありますが、4 の方が左側に位置しているためです。 解法のアプローチ この問題は、幅優先探索(BFS)を使って木をレベルごとに走査することで効率的に解けます。各レベルの最初のノード(=そのレベルの最も左のノード)の値を記録していき、すべてのレベルの走査が完了した時点で記録されている値が、最も深いレ
-
Pythonで最長のバランス括弧部分列の長さを求めるプログラム
問題概要 文字列 s が与えられます。この文字列には括弧「(」と「)」が含まれており、その中からバランスの取れた(対応関係が成立している)括弧の部分列として最も長いものを見つけ、その長さを返すことが目標です。 たとえば、入力が s = ())(()( の場合、出力は 4 になります。「(」と「)」を選び抜いて ()() というバランスの取れた部分列を作れるためです。 解法のアプローチ この問題は、文字列を後ろから走査することで線形時間で解けます。閉じ括弧を先に確保しておき、開き括弧が出てきたときに対を成立させるという発想です。手順は以下の通りです。 結果を格納する変数 res を 0 で初
-
Pythonで二分木をジグザグ(左右交互)にレベル順トラバースする方法
二分木が与えられたとき、各レベルの値を「左から右」「右から左」と交互に切り替えながら出力することを考えます。これはいわゆるジグザグ(鋸歯状)レベル順トラバースと呼ばれる問題です。例えば、次のような二分木が入力だとします。この場合、出力は [5, -10, 4, -2, -7, 15] となります。アルゴリズムの考え方この問題は、スタックを2つ使うことで効率的に解けます。奇数レベルと偶数レベルで子ノードの追加順序を入れ替えるのがポイントです。手順は以下の通りです。root が null の場合は、空のリストを返すs1 := root を格納したリストを作成s2 := 空のリストを作成res :=
-
Pythonで二分探索木をレベル順(幅優先)走査によりリンクリストへ変換するプログラム
二分探索木が与えられたとき、レベル順走査(幅優先走査:BFS)を用いて、それを単方向リンクリストへ変換することを考えます。木の各ノードの値を、上の階層から左から右の順にたどりながら、連結リストとしてつなげていくイメージです。例えば、次のような二分木が入力として与えられた場合を考えてみましょう。この場合、出力は [5, 4, 10, 2, 7, 15] となります。解法のアプローチこの問題は、キュー(待ち行列)を使った典型的な幅優先探索のパターンで解くことができます。手順は以下の通りです。head := ダミー用の新しいリンクリストノードを作成currNode := head(現在の追加位置を指
-
Pythonでソート済み連結リストから二分探索木(BST)を構築する方法
サイズ n のソート済み連結リストが与えられたとき、そのリストから二分探索木(Binary Search Tree / BST)を構築することを考えます。具体的には、k 番目に小さい値(ただし k = floor(n / 2))をルートとし、k 番目のノードより左側にある要素から左部分木を、右側にある要素から右部分木を再帰的に構築していきます。例えば、入力が [2, 4, 5, 7, 10, 15] の場合、出力は次のような二分探索木になります。解法のアプローチこの問題は、低速ポインタ(slow)と高速ポインタ(fast)を活用した「フロイドの循環検出」でもおなじみのテクニックで解くことができ