原题地址

方法1-贪心

思路

就是按照题意来从左到右分析字符串 S ,得出不相交的区间。
具体步骤如下:

  • 从第一个字母开始,假设是 'a' ,第一个区间一定包含最开始的 'a' 和结束的 'a'
  • 然后分析第二个字母,假设是 'b'
  • 如果开始的 'b' 在第一个区间之内,并且结束的 'b' 在第一个区间之外了,那么第一个区间就被扩充了,区间右端点应该改为 'b' 的结束位置;
  • 举例来说,字符串 S='abbbabed''a' 的开始和结束位置分别为 0, 4 ,但是第一个区间的左右端点分别为 0, 5

所以我们的算法就是:遍历字符串,对于遇到的每一个字母,寻找他的结束位置,看是否能够更新当前区间的右侧端点。

我的想法如下:

  1. 定义一个有序字典,遍历一遍字符串,来得到每个字符所出现的所有位置(用列表记录);形如 {'a': [0, 3, 6], ...}
  2. 然后遍历有序字典,用一个二维列表,记录每个字符出现的开始位置和结束位置;形如 [[0, 5], [1, 3], ...]
  3. 然后再遍历二维列表,对于列表中的每一个字符的开始和结束位置:
    • 如果字符的开始位置和结束位置都位于当前区间内,则不更新当前区间,继续遍历下一个字符;
    • 如果字符的开始位置在当前区间内,结束位置在外,则更新当前区间的右侧端点;
    • 如果字符的开始位置在当前区间之外,则再开始新的区间;

于是就有了如下代码(太麻烦啦写的!!)

代码1

  1. class Solution:
  2. def partitionLabels(self, S: str) -> List[int]:
  3. from collections import OrderedDict
  4. oDict = OrderedDict()
  5. for i in range(len(S)): # 得到有序字典
  6. if S[i] not in oDict:
  7. oDict[S[i]] = [i]
  8. else:
  9. oDict[S[i]].append(i)
  10. sList = []
  11. for lst in oDict.values():
  12. sList.append([lst[0], lst[-1]]) # 得到二维列表,里面存的是每个字符的开始和结束位置
  13. ans = []
  14. i = 0
  15. start = end = 0
  16. while i < len(sList): # 遍历二维列表
  17. # 初始化当前区间
  18. start = sList[i][0]
  19. end = sList[i][-1]
  20. for j in range(i+1, len(sList)):
  21. print(i ,j)
  22. if sList[j][0] > end: #当前区间无法再更新,开始新的区间(对应第三种情况)
  23. ans.append(end-start+1)
  24. i = j-1
  25. break
  26. else:
  27. if sList[j][-1] > end: # 更新当前区间的右端点(第二种情况)
  28. end = sList[j][-1]
  29. if j == len(sList)-1: #遍历完了,结束掉循环
  30. i = j
  31. i += 1
  32. ans.append(end-start+1)
  33. return ans

时空复杂度

因为定义了有序字典和列表,空间复杂度毫无疑问是 O(N)
虽然下面有两重循环,但仔细观察就知道只遍历了二维数组一次,而且二维数组中的元素个数肯定等于 N ,所以时间复杂度也为 O(N)

代码2

官方给出的思路与我的一模一样,但是做法更好,写的代码也棒多了,附上官方代码

  1. class Solution(object):
  2. def partitionLabels(self, S):
  3. # 通过enumerate得到每个字符的结束位置,(没有记录开始位置)
  4. last = {c: i for i, c in enumerate(S)}
  5. j = anchor = 0 #anchor 和 j 来表示当前区间的首尾。
  6. ans = []
  7. for i, c in enumerate(S):
  8. j = max(j, last[c])
  9. if i == j:
  10. ans.append(i - anchor + 1)
  11. anchor = i + 1
  12. return ans
  13. 作者:LeetCode
  14. 链接:https://leetcode-cn.com/problems/partition-labels/solution/hua-fen-zi-mu-qu-jian-by-leetcode/
  15. 来源:力扣(LeetCode
  16. 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时空复杂度

同代码1

代码3

cpp版

  1. class Solution {
  2. public:
  3. vector<int> partitionLabels(string S) {
  4. // 得到每个字符的右界
  5. int last[26];
  6. for(int i=0; i<26; i++) last[i] = -1;
  7. for(int i=0; i<S.size(); i++) last[S[i]-'a'] = i;
  8. vector<int> v;
  9. int begin = 0, end = 0;
  10. for(int i=0; i<S.size(); i++){
  11. if(last[S[i]-'a'] > end){
  12. end = last[S[i]-'a'];
  13. }
  14. else if(i == end){
  15. v.push_back(end-begin+1);
  16. begin = end = i+1;
  17. }
  18. }
  19. return v;
  20. }
  21. };