題目出處
1520. Maximum Number of Non-Overlapping Substrings
難度
hard
題目分類
Hash Table, String, Greedy, Sorting
2026-09-18 一刷
個人範例程式碼 - 一刷 (2026/09/18)
class Solution:
def maxNumOfSubstrings(self, s: str) -> list[str]:
first, last = {}, {}
# fill up the first and last
for i, c in enumerate(s):
if c not in first:
first[c] = i
last[c] = i # edge: if only one, start = end
intervals = []
# traverse first (parse all letters start idx)
for c, start in first.items():
# fix the start letter, then extend the length to valid
current_end = last[c]
idx = start
valid = True
# extend the substring and check the condition
while idx < current_end:
idx += 1
current_c = s[idx]
# if start before the front, not valid
if first[current_c] < start:
valid = False
break
# if end behind the current_end, extend the current_end
current_end = max(current_end, last[current_c])
if valid:
# update ans
intervals.append((start, current_end))
res = []
intervals.sort(key = lambda x: x[1]) # sort by end (greedy)
prev_end = -1
for start, end in intervals:
if start > prev_end:
prev_end = end
res.append(s[start:end+1]) # + 1 for last letter
return res
算法說明
intervals 的進階題目,主要會分成三大步驟:
- 維護好每一個單字的 start, end 位置
- 處理合法的 substrings (intervals)
- 最後,所有紀錄好合法的 substrings,使用 greedy 的方式進行區間重疊處理找到最終答案。
1. 整理好每一個字母的 start, end 位置
只要某字母出現過,該字母所有出現位置都要包含在 substring 內,
我們先把完整字串整個掃過一次,把每一個文字 start, end 位置都紀錄好。
2. 處理合法的 substrings (intervals):
剛剛只有找到每一個字母的頭尾,現在要處理的是合法區間,也就是題目條件 (只要出現單一文字,那就需要包含全部文字)
包含兩種情況
- 新文字起點出現當前區間左側,此區間不可能成立。(可以繼續處理下一組開頭)
- 新文字終點出現在此區間之後,區間終點可以往後延伸,並繼續判斷。
3. 最終區間答案處理
這裡我們使用 greedy 的方式進行區間重疊處理找到最終答案。
具體來說,我們先把所有合法區間的 end 位置排序好 (sort),然後開始掃。
- 因為 end 已經排序好,理想情況是毫無重疊,那這樣 start 也自然都會在前。
- 當真的發生重疊的情況,那也會因為 end 先出現的關係,後出現的 end (數字會更大),有重疊的部分會被排除。
透過判斷有無 start > prev_end 。 (比上一個區間的尾巴更右側) 才可以加入新答案。
Time Complexity
O(n * 26) = O(n) # 英文字母 26 個
Space Complexity
O(26) = O(1) # 英文字母 26 個
Boundary conditions
- 留意字串切片邊界 s[start:end+1] # 需多一個才能包含最後值