今日は,ZigZag Conversionを解きました.その中で学んだことを記録しておきます.
なお,私はPython初心者かつ,LeetCodeのような問題も始めたばかりなので,間違いの指摘や,アドバイスなどがあればお待ちしております.
#問題設定
s="PAYPALISHIRING"という文字列に対し,numRows=3が与えられたとき,
P A H N
APLSIIG
Y I R
のようにギザギザになる.outputは各行を左から順に並べた"PAHNAPLSIIGYIR"となる.
最初に書いたコード
方針
- 与えられた文字列
s
について,先頭から順に0,1,...,(numRows-1),(numRows-2),...,1,0,...のようにkey=0,1,...,numRows-1を割り当てる.- インクリメント/デクリメントを判断する識別子
Inc
が必要?
- インクリメント/デクリメントを判断する識別子
- keyの小さいほうから順に結合し,それをoutputとして返す.
- どうすれば文字列を結合できる?
以上の方針から,次のようなコードを書いた:
class Solution(object):
def convert(self, s, numRows):
"""
:type s: str
:type numRows: int
:rtype: str
"""
#エッジケースの処理
if(numRows <= 1):
return s
d = defaultdict(list)
Inc = True
key = 0
# label 0, 1,2,...,numRows,numrows-1,...,1,0,...
for i in range(len(s)):
d[key].append(s[i])
if(key == numRows - 1):
Inc = False
elif(key == 0):
Inc = True
if(Inc == True):
key += 1
else:
key -= 1
# join d
ans = ''
for i in range(numRows):
ans += ''.join(d[i])
return ans
Runtime: 64ms
Memory: 12.8MB
つまづいた点
同一のkeyを持つ要素の格納方法
同一のkey
を持つs[i]
に対して,
d[key] = s[i]
とすると,値が上書きされてしまった.
これは,リストのメソッドappend()
を用いて,末尾に要素を追加するようにして解決した.
リスト関係のメソッドは他にも将来使いそうなものがたくさんあるので,今後勉強していきます.
リストを文字列に変換する方法
forループ直後のd
は,
{0: [u'P', u'A', u'H', u'N'],
1: [u'A', u'P', u'L', u'S', u'I', u'I', u'G'],
2: [u'Y', u'I', u'R']}
のようになっていた.
forループを使って結合していくのも面倒だなと思って著と調べてみたら,リストを文字列に変換してくれるjoin()
メソッドを見つけた.例えば,
d[0] = ['P','A','H','N']
'.'.join(d[0]) # => 'P.A.H.N'
のようになる.
今回は''
内に何も入れなければ単純に連結することになる.
そして,join
した文字列をkey
の小さい順にans
へ足しこんでいけば,所望のoutput
が得られる.
コードの改善
LeetCodeでは,他人の考えたコードを見れる「Discuss」がとても良い.
この問題ではこちらを参考にさせてもらった.
改善版のコードは次に示す:
class Solution(object):
def convert(self, s, numRows):
"""
:type s: str
:type numRows: int
:rtype: str
"""
if(numRows <= 1):
return s
d = [""] * numRows
Inc = True
key = 0
for i in range(len(s)):
d[key] += s[i]
if(key == numRows - 1):
Inc = False
elif(key == 0):
Inc = True
if(Inc == True):
key += 1
else:
key -= 1
return ''.join(d)
Runtime: 28ms(<= 64ms)
Memory:12.7MB(<=12.7MB)
で,実行時間を1/2以下にすることができた.
リスト配列の初期化
例えば,
L = ['','','']
といったリスト配列を作るとき,
L = [''] * 3
とすれば,上と同等のものが出来ることを知った.
今回は0~numRows-1までのnumRowsこの要素が必要であることが明らかであるため,こちらのほうが柔軟かつ明示的になるだろう.
keyごとの分類の改善
今思えば,同一のkey
の場合はappend()
するよりも,最初から結合したほうが1つ手順が減らせることに気づいた.
このようにすることで,forループ後にもう一度forループを用いて文字列を結合せずに,''.join()
のみで済む.