题目:字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一个字母只会出现在其中的一个片段。返回一个表示每个字符串片段的长度的列表。
例子: 输入:S = “ababcbacadefegdehijhklij” 输出:[9,7,8] 解释: 划分结果为 “ababcbaca”, “defegde”, “hijhklij”。 每个字母最多出现在一个片段中。 像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。
首先看到题目赶紧有点复杂,想了几种方法都感觉有点复杂。后来发现只需要一直向后遍历即可,当出现更大的 lastIndex 就更新一下,遍历到 lastIndex 为止。这就是一个片段,后面在 lastIndex 的下一位继续重复一直到字符串的末尾。
比如示例中: 1.起点为0;从 a 开始遍历,a 的 lastIndex 为8;temp 移到 b ,取得 b 的 lastIndex 为 5;temp 移到 a ,跳过 … temp 移到 c ,取得 c 的 lastIndex 为7;temp 移到 a ,temp==lastIndex,len=lastIndex-start+1添加 len 到答案。 2.起点为上一次的 lastIndex 下一位;从 d 开始遍历,d 的 lastIndex 为14;temp 移到 e ,取得 e 的 lastIndex 为15,大于原本的 lastIndex,更新其为15;… ;同上添加到答案。 3.起点为上一次的 lastIndex 下一位;从 h 开始遍历,h 的 lastIndex 为16;temp 移到 i,取得 i 的 lastIndex 为22,大于原本的 lastIndex ,更新为22;temp 移到 j,取得 j 的 lastIndex 为 23,大于原本的 lastIndex,更新为23;temp 移到 h,h 的 lastIndex 小于 lastIndex;temp 移动到 k,取得 k 的 lastIndex 为20;…;添加答案;
过程写的有些繁琐,看的都不耐烦了,所以里面有许多可以优化的地方嘛~ 1.可以用一个 map 存储已经遍历过的字符,如果遍历过就不会再取该字符的 lastIndex 了; 2.如果有片段长度为1的字符,判断到的时候直接跳出后面的代码; 3.最后一个片段中,肯定会存在一个字符的 lastIndex 等于 S.length()-1,这个时候就可以直接添加该片段然后返回,避免后序多余的遍历。
然后可以得到代码如下:
class Solution { public List<Integer> partitionLabels(String S) { List<Integer> ans = new LinkedList<>(); if (S.length() == 0) return ans; Map<Character, Integer> map = new HashMap<>();//保存遍历记录 int i = S.lastIndexOf(S.charAt(0)), temp = 0; map.put(S.charAt(0), i); while (i < S.length()) { int start = temp; while (temp < i) { //函数结束表示找到片段 char ch = S.charAt(temp); int index; /*如果已经遍历过该字符直接temp++跳过 *如果没有遍历过 先判断是否为单个字符的片段或者最后一个片段 *再取该字符的lastIndex和记录比较 *如果大于则更新 小于等于不做操作 */ if (!map.containsKey(ch)) { index = S.lastIndexOf(S.charAt(temp)); if (index == S.length() - 1) {//最后一个片段 添加后直接返回 ans.add(index - start + 1); return ans; }else if(index == start)break;//单个字符片段 直接添加 map.put(ch, index); if (index > i) i = index; } temp++; } ans.add(i - start + 1); temp = i+1; if(temp<S.length())i = S.lastIndexOf(S.charAt(temp)); else break; } return ans; } }