Pythonで接続して作れる最長スティックの長さを求めるプログラム
整数のリスト sticks があるとします。リストの各要素は両端を持つ1本の棒(スティック)を表しており、各端の値は 1〜6 の範囲に収まっています。2本の棒は、どちらかの端の値が一致していれば連結することができ、連結後の棒の端は「余った側の端」になり、全体の長さは伸びていきます。このとき、作れる中で最も長い棒の長さを求めるのがこの問題の目的です。
たとえば、入力が sticks = [[2, 3], [2, 4], [3, 5], [6, 6]] の場合、出力は 3 になります。[2, 3] と [2, 4] を連結して [3, 4] を作り、さらにそれと [3, 5] を連結することで [4, 5] という棒が得られるためです。
解き方のアプローチ
この問題は、棒を「頂点(端の数字)」と「辺(棒そのもの)」からなるグラフとみなし、深さ優先探索(DFS)で最長の経路(連結数)を求めることで解けます。手順は以下の通りです。
dfs()関数を定義します。引数は node(現在の頂点)、edge_idx(辺のインデックス)、visited(使用済みの辺を記録するセット)です。edge_idxが null でない場合:edge_idxがすでに visited に含まれていれば 0 を返します。edge_idxを visited に追加します。res := 0と初期化します。g[node]に属する各 e_idx について:n_node := sticks[e_idx][1] == nodeならsticks[e_idx][0]、そうでなければsticks[e_idx][1](反対側の端)とします。res := max(res, 1 + dfs(n_node, e_idx, visited))で最大値を更新します。
edge_idxが非ゼロの場合、visited から edge_idx を削除して元に戻します。resを返します。
メイン処理では以下を実行します。
sticksをタプルのリスト[(s[0], s[1]) for s in sticks]に変換します。空のセット
verticesと、空のマップg(defaultdict)を用意します。各インデックス i と各 edge について:
g[edge[0]]とg[edge[1]]に i を追加します。edge[0]とedge[1]を vertices に追加します。
res := 0とし、vertices 内の各頂点 v に対してres := max(res, dfs(v, None, set()))を計算します。res - 1を返します。連結した棒の本数(辺の数)がそのまま長さになるため、1 を引いています。
実装例
理解を深めるために、以下の実装例を見てみましょう。
from collections import defaultdict class Solution: def solve(self, sticks): def dfs(node, edge_idx, visited): if edge_idx is not None: if edge_idx in visited: return 0 visited.add(edge_idx) res = 0 for e_idx in g[node]: n_node = sticks[e_idx][0] if sticks[e_idx][1] == node else sticks[e_idx][1] res = max(res, 1 + dfs(n_node, e_idx, visited)) if edge_idx: visited.remove(edge_idx) return res sticks = [(s[0], s[1]) for s in sticks] vertices = set() g = defaultdict(set) for i, edge in enumerate(sticks): g[edge[0]].add(i) g[edge[1]].add(i) vertices.add(edge[0]) vertices.add(edge[1]) res = 0 for v in vertices: res = max(res, dfs(v, None, set())) return res - 1 ob = Solution() sticks = [ [2, 3], [2, 4], [3, 5], [6, 6] ] print(ob.solve(sticks))
入力
sticks = [ [2, 3], [2, 4], [3, 5], [6, 6] ]
出力
3
-
Pythonで「a」から始まる連続増加部分文字列の最長長さを求めるプログラム
問題の概要小文字の英字と「?」記号を含む文字列 s が与えられます。各「?」については、削除するか、任意の小文字の英字に置き換えることができます。このとき、「a」で始まる連続して増加する部分文字列(例:abcdef のようにアルファベット順に1文字ずつ進む文字列)の最長の長さを求める必要があります。例えば、入力が s = vta???defke の場合、出力は 6 になります。これは、s を vtabcdefke に変換できるためです。変換後の文字列には abcdef という連続増加部分文字列が含まれており、これが「a」で始まる最長のものとなります。解法のアプローチこの問題は、文字列を一度走査
-
Pythonでn分木の最長パスの長さを求めるプログラムの書き方
各要素が (u, v) という形式を持ち、u が v の親であることを表す辺リストが与えられているとします。このとき、木の中で最も長いパスの長さを求める必要があります。ここでいうパスの長さとは、「そのパスに含まれるノードの総数 + 1」のことです。 たとえば、入力が下図のような n 分木だった場合を考えてみましょう。 この場合の出力は 5 になります。なぜなら、パス [1, 4, 5, 7] には合計 4 つのノードが含まれており、パスの長さは 1 + 4 = 5 となるからです。 解き方のアプローチ この問題は、幅優先探索(BFS)を2回実行するという定番テクニックで効率よく解けます。まず