【LeetCode】763. Partition Labelsを解く
問題概要
小文字のアルファベットからなる文字列s
が与えられる.このとき,「各文字がただ一つの部分文字列に含まれる」という条件を満たすように,出来るだけ多くの部分文字列に分割することを考える.
上記の条件を満たす,各部分文字列のサイズからなるリストを返せ.
例:
Input: S = "ababcbacadefegdehijhklij"
Output: [9,7,8]
Explanation:
ababcbaca | defegde | hijhklij
のように分割する.
制約
1 \leq S.length \leq 500 - Sは,a-zの小文字のアルファベットからなる
考えたこと
入力s
をleft = 0
から順にみていき,
- 現在見ているアルファベット
s[left]
が最後に出現するインデクスright
を保持 -
right
までに含まれるアルファベットについて,そのアルファベットが最後に出現するインデクスの内最大の値であるnext
を保持-
のとき:right < next right
=next
に更新し,新しいright
について②の操作を行う -
right
と現在見ているアルファベットのインデクスが等しいとき:
res
にright - left + 1
を追加
left
=right
+ 1に更新
-
-
right
が最後のインデクスになるまで①-③を繰り返す
という手順で処理すればよさそう.
以下,例題を用いて実際の動きを見てみる:
ステップ1:
先頭のアルファベットa
が最後に現れるのは9
番目である.
a b a b c b a c a d e f e g d e h i j h k l i j
↑ ↑
left right
s[left:right+1]
に含まれるb
,c
は全てこの部分文字列に含まれているため,right
の更新は行われない.従って,一つ目の部分文字列はs[0:9] = 'ababcbaca'
となる.
ステップ2:
一つ目の分割点が分かっているため,left
= right
+ 1に更新する.
s[left] = 'd'
が最後に現れるのは14
番目である.
a b a b c b a c a | d e f e g d e h i j h k l i j
↑ ↑
left right
ただし,s[left:right+1]
に含まれる'e'が最後に現れるのは15
番目でright
より大きい値であるため,right = 15
に更新する.
a b a b c b a c a | d e f e g d e h i j h k l i j
↑ ↑
left right
s[left:right]
に含まれるd
,e
,f
,g
は全てこの部分文字列に含まれているため,right
の更新は行われない.従って,二つ目の部分文字列はs[9:16] = 'defegde'
となる.
ステップ3:
まず,left
= right
+ 1に更新する.
s[left] = 'h'
が最後に現れるのは19
番目である.
a b a b c b a c a | d e f e g d e | h i j h k l i j
↑ ↑
left right
ただし,s[left:right]
に含まれるi
,j
はright
以降にも存在する.
i
が最後に現れるのは22
番目でright
より大きいため,right = 22
に更新する.
a b a b c b a c a | d e f e g d e | h i j h k l i j
↑ ↑
left right
s[left:right]
に含まれるj
はright
以降にも存在する.
j
が最後に現れるのは23
番目でright
より大きいため,right = 23
に更新する.
a b a b c b a c a | d e f e g d e | h i j h k l i j
↑ ↑
left right
これはs
の最後の文字であるためこれ以上right
の更新は発生しない.
以上より,例題は以下のように分割することができる.
a b a b c b a c a | d e f e g d e | h i j h k l i j |
実際のコードは以下のようになる:
class Solution(object):
def partitionLabels(self, S):
"""
:type S: str
:rtype: List[int]
"""
last = {c: i for i, c in enumerate(S)} # 各アルファベットが最後に現れるインデクス
res = []
left, right = 0, 0
for i, c in enumerate(S):
right = max(right, last[c])
if i == right:
res.append(right - left + 1)
left = right + 1
return res
上記プログラムでは,各アルファベットが最後に現れるインデクスをあらかじめlast
として算出することで計算回数を減らすように工夫している.
Discussion