【Python】優先順位付き投票から最終ランキングを上位順に求めるプログラム
問題の概要
文字列のリスト votes が与えられます。各要素は小文字のみで構成され、候補者への投票を「最も優先度が高い順位から低い順位へ」の順に表しています。候補者の順位は、まず第1優先として受け取った票数で決まります。ここで同点が発生した場合は、次に高い優先度での得票数を比較し、それでも決まらない場合はアルファベット順で順位を確定します。このルールに基づき、チーム(候補者)の最終ランキングを上位から下位の順に出力します。
入力例と考え方
たとえば votes = ["zyx", "zxy", "xyz"] の場合、出力は "zxy" になります。
- 「z」は第1優先の票を最も多く獲得したため1位。
- 「x」は第1優先の票数が2番目に多い。
- 「y」は第1優先の票を1票も得られなかったため最下位。
解法のアプローチ
以下の手順で問題を解きます。
count:= votes 内の文字列の長さ(=候補者の総数)cand:= 空のマップ。キーごとに長さcountのリスト(初期値はすべて0)を保持する- votes の各要素
vについて処理を行う:vの各インデックスiと文字cに対し、cand[c][i]を1増やす
candの各項目を得票数の降順でソートする。値が同じ場合はアルファベット順に並べる- ソート済みの要素を連結して文字列として返す
実装例
from collections import defaultdict class Solution: def solve(self, votes): count = len(votes[0]) cand = defaultdict(lambda: [0] * count) for v in votes: for i, c in enumerate(v): cand[c][i] += 1 return "".join(sorted(cand.keys(), key=lambda x: (cand[x], -ord(x)), reverse=True)) ob = Solution() votes = ["zyx", "zxy", "xyz"] print(ob.solve(votes))
入力
["zyx", "zxy", "xyz"]
出力
zxy
コードのポイント
ソートのキーには (cand[x], -ord(x)) を指定し、reverse=True で降順ソートしています。Pythonではリスト同士を比較すると要素を先頭から順に比較するため、第1優先・第2優先…という優先順位付けが自然に実現できます。また、同点の場合は -ord(x) が大きい方(=文字コードが小さい、つまりアルファベットで早い文字)が先に来るようになっているため、「同点ならアルファベット順」という条件も満たされます。
計算量
有権者数を n、候補者数を m とすると、集計には O(n × m)、ソートにはキー比較としてリスト比較が含まれるため O(m² log m) かかります。ただし候補者数はアルファベット26文字に制限されるため、実用上は非常に高速に動作します。
-
Pythonで行列の転置を求めるプログラム
この記事では、与えられた問題に対する解法とアプローチについて詳しく解説します。 問題文 ある行列が与えられたとき、その転置を同じ行列に格納し、結果を表示する必要があります。 行列の転置とは、行を列に、列を行に入れ替えたものです。言い換えれば、行列Aの転置は、要素A[i][j]をA[j][i]と入れ替えることで得られます。 実装例 N = 4 def transpose(A): for i in range(N): for j in range(i+1, N): A[i][j], A[j][i] = A[j][i], A[i][j] # ドライ
-
Pythonで配列(リスト)の合計を求める方法をわかりやすく解説
この記事では、配列(リスト)の合計値を求めるという問題に対して、Pythonでの解決策とアプローチをわかりやすく解説します。 問題の定義 配列が入力として与えられたとき、その配列に含まれるすべての要素の合計を計算することを目標とします。 例えば、[1, 2, 3, 4, 5] という配列が与えられた場合、出力は 15 になります。 アプローチ1:ループを使った素朴な方法(総当たり法) 最も基本的な方法は、リストを先頭から順に走査し、各要素を合計用の変数に加算していくやり方です。手順は以下の通りです。 合計を格納する変数を 0 で初期化します。 for ループでリストの各要素を取り出し、順番に