経緯
A問題なので楽勝かと思いきや、自分はパッと鮮やかな解答が思いつきませんでした。
(時間がかかるのも嫌なので結局、8通りの場合分けをベタ書きするというセンスないコードを提出してしまいました、無念……。)
ヒントを得ようと上位者のSubmissionを眺めていると、itertoolsを使用した鮮やかな解答が多く見られましたが、最近Pythonを触り始めた私にはgroupbyがチンプンカンプンでした。今回、理解したので内容を記しておきます。
問題
AtCoder 町の、ある連続した$3$日間の天気の記録があります。天気の記録は長さ$3$の文字列$S$で表され、$i(1\leq i\leq 3)$日目の天気は$i$文字目が'S'のとき晴れ、'R'のとき雨でした。
天気が雨である日が連続していた最大の日数を求めてください。制約
$\left| S \right| = 3$
$S$の各文字は'S'または'R'である
要求は非常にシンプルですが、単純に'R'の個数で判定すると'RSR'のパターンでNGとなります。
しょぼい解答
拡張性が皆無な書き方をすれば以下のようになります。ゴリ押しですね。
s = input()
if s == 'RRR':
res = 3
elif s =='SRR':
res = 2
elif s =='RSR':
res = 1
elif s =='RRS':
res = 2
elif s =='RSS':
res = 1
elif s =='SRS':
res = 1
elif s =='SSR':
res = 1
else:
res = 0
print(res)
普通の解答
おそらくこの程度が期待されているコードだと思われます。
s = input()
if 'RRR' in s:
res = 3
elif 'RR' in s:
res = 2
elif 'R' in s:
res = 1
else:
res = 0
print(res)
上位者の解答例
morio__さんという方が下記のようなコードを提出されていました。
黄コーダーの方で、Pythonで最速の開始36秒でのACということで完全にレベチです。
from itertools import groupby
res = 0
s = input()
for k, v in groupby(s):
if k == 'R':
res = max(res, len(list(v)))
print(res)
汎用性が非常に高くて美しいですね。
指定するキーの部分を書き換えるだけで常に与えられた文字列の中の最長の連続数を取得できます。
コードとはかくあるべきと感じます。
groupbyについて
groupbyの公式ドキュメントです。
itertools.groupby(iterable, key=None)
多次元入力に対して任意のカラムでグルーピングも出来るようですが、今回は1次元配列で見てみます。
こんな挙動のようです。
# itertoolsからgroupbyをインポート(itertoolsには他にも便利なツールがたくさんありました)
from itertools import groupby
# groupbyする1次元配列
mylist = [0,0,0,1,1,2,2,2,1,1,1]
# groupbyはイテラブルでkeyとgroupが返る
for key, group in groupby(mylist):
# groupの各要素をリストにキャストして出力
print(key, list(group))
# 出力
# 0 [0, 0, 0]
# 1 [1, 1]
# 2 [2, 2, 2]
# 1 [1, 1, 1]
groupby
で得られるgroup
はあくまでイテラブルな'オブジェクト'なので、扱う際にはリストにキャストしてあげないといけないみたいです。
ちなみにgroup
の型をtype(group)
で出力すると<class 'itertools._grouper'>
でした。
理解した内容
キーが'R'のグループに対し、len(list(v))
でグループの要素数を取得していき、最大のものを出力しているということですね。
非常に鮮やかで勉強になりました。自分ももっと精進します。