Problem:
A string S of lowercase letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.
Example 1:
Input: S = “ababcbacadefegdehijhklij” Output: [9,7,8] Explanation: The partition is “ababcbaca”, “defegde”, “hijhklij”. This is a partition so that each letter appears in at most one part. A partition like “ababcbacadefegde”, “hijhklij” is incorrect, because it splits S into less parts.
Note:
思路: 很暴力,直接找可以Partition的位置,如果不能Partition,继续向后搜索直到找到第一个可以Partition的位置为止,这样剩余问题就是原问题的子问题了。
初始版本如下:
public List<Integer> partitionLabels(String S) { List<Integer> ans = new ArrayList<>(); if (S.length() == 0) return ans; char[] cs = S.toCharArray(); StringBuilder sb = new StringBuilder(); int i = 0; for (; i < cs.length; ++i) { sb.append(cs[i]); if (part(sb, i, S)) { ans.add(sb.length()); break; } } List<Integer> sub = partitionLabels(S.substring(i + 1)); for (int hello : sub) ans.add(hello); return ans; } public boolean part(StringBuilder sb, int i, String S) { if (sb.toString().isEmpty()) return false; for (int j = i + 1; j < S.length(); ++j) { String letter = S.substring(j, j + 1); if (sb.toString().contains(letter)) return false; } return true; }
再精简一点,因为调用原函数,可以在for循环中完成,所以有:
public List<Integer> partitionLabels(String S) { List<Integer> ans = new ArrayList<>(); char[] cs = S.toCharArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < cs.length; ++i) { sb.append(cs[i]); if (part(sb, i, S)) { ans.add(sb.length()); sb = new StringBuilder(); } } return ans; } public boolean part(StringBuilder sb, int i, String S) { if (sb.toString().isEmpty()) return false; for (int j = i + 1; j < S.length(); ++j) { String letter = S.substring(j, j + 1); if (sb.toString().contains(letter)) return false; } return true; }
万幸此答案没有超时,实际上我们还可以采用贪心的做法,降低时间复杂度。上个版本中,还需要计算StringBuilder的字符串中的每个字符是否在后续字符中出现过,实际上没有必要,我们只要记录StringBuilder中的每个字符出现的最后一个位置在哪,这样就避免每次都判断一遍,而是利用字符的最后位置直接判断。其次很重要的一点,字符串的partition的依据是:字符串中每个字符最后出现位置的整体最大值。
Java版本:
public List<Integer> partitionLabels(String S) { List<Integer> ans = new ArrayList<>(); char[] cs = S.toCharArray(); int n = cs.length; int[] last = new int[32]; for (int i = 0; i < n; ++i) { last[cs[i] - 'a'] = i; } int pre = -1; int max = 0; for (int i = 0; i < n; ++i) { if (last[cs[i] - 'a'] > max) max = last[cs[i] - 'a']; if (max == i) { ans.add(max - pre); pre = max; max = max + 1; } } return ans; }
Python版本:
class Solution(object): def partitionLabels(self, S): """ :type S: str :rtype: List[int] """ lst = {} n = len(S) for i, c in enumerate(S): lst[c] = i ans = [] max = 0 pre = -1 for i in range(n): if lst[S[i]] > max: max = lst[S[i]] if max == i: ans.append(max - pre) pre = max max = max + 1 return ans
本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。
我来说两句