刷题日期: 2020年10月22日 00:50
题目描述
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。
示例
输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。
提示:
S的长度在[1, 500]之间。
S只包含小写字母 ‘a’ 到 ‘z’ 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-labels
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
### 贪心
- 一开始想用贪心的方式去解决这个问题,后来绘制出过程图发现,其分割是固定的。初次分割,必须是根据首字母对整个字符串分割成两半,分别为L_left和L_right。后续是一样的分割方式。直到最后无法分割为止。
- 此时:从左到右,所有叶子节点对应的字符串的长度组成的List即为所求。
初始
python 字典 / map / 哈希表
- 因为分割是固定的。因此,只需要记录每一个字母的最左侧位置和最右侧的位置,即可完整保存分割所需要的信息。因此,第一次遍历整个字符串,保留所有字母的最左侧和最右侧的数据。若仅存在一个,则最右侧索引记为 -1.例如:
eaaaabaaec
{‘e’: 0, ‘a’: 1, ‘b’: 2, ‘c’: 3}
[0, 8], [1, 7], [5, -1], [9, -1]
- 第二次遍历,从第一个list [left, right]开始遍历,以minIndex和 maxIndex分别表示,左侧最小值和右侧最大值。
- 当maxIndex 小于当前List的左侧节点时,即可进行一次划分
- 当maxIndex 为-1 时即可进行一次划分,
最终的代码
def partitionLabels(S):
"""
:type S: str
:rtype: List[int]
"""
charDict = {}
indexList = []
for i,s in enumerate(S):
if s in charDict.keys():
index = charDict[s]
indexList[index][1] = i
else:
charDict[s] = len(indexList)
indexList.append([i,-1])
result = []
minIndex = indexList[0][0]
maxIndex = indexList[0][1]
for index,i in enumerate(indexList):
if index == 0:
continue
if maxIndex == -1:
minIndex = i[0]
maxIndex = i[1]
result.append(1)
elif maxIndex < i[0]:
result.append(maxIndex - minIndex + 1)
minIndex = i[0]
maxIndex = i[1]
else:
maxIndex = max(maxIndex,i[1])
# print(("%s :: %s"%(minIndex,maxIndex)))
if maxIndex == -1:
result.append(1)
else:
result.append(maxIndex - minIndex + 1)
# 用于调试
# return result,indexList,charDict
return result
结果:
后续优化方向
- 保留尽可能少的信息;
- 是否可以仅遍历一次即得出结果。
- 使用提示信息进行结构上的优化