LC763-划分字母区间

116 阅读1分钟

题目名称:划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表。

 

示例 1:

输入: s = "ababcbacadefegdehijhklij"
输出: [9,7,8]
解释:
划分结果为 "ababcbaca""defegde""hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。 

示例 2:

输入: s = "eccbbbbdec"
输出: [10]

提示:

  • 1 <= s.length <= 500
  • s 仅由小写英文字母组成

思路分析

遍历一遍找到每个字母出现的最后位置 第二次遍历不断更新中止下标end,end = Math.max(end,last[char]) 直到end后无重复字母 得出一个区间 这样划分的区间是最多的

从i出开始遍历,判断当前遍历是否超出了记录的最远处值,如果未超过,更新bound,且继续向后遍历,如果超出了,说明可以划分一个区间。 举例说明,我们首先记录每个字母出现的最远位置。然后,对于"ababcbacadefegdehijhklij"来说,我们首先从a开始,a出现的最远位置索引为8,bound记做8。继续向后遍历,遍历到b,b出现的最远距离为5,bound不需要更新,继续向后,后面依次,直到索引遍历到8,说明之前的字母的索引值最大即到此,可以做出一个划分。然后更新起始位置,继续做如上的操作。 本题中,我们用i表示开始,cur表示当前遍历的位置。当可以做出一个划分时,片段长度为cur-i+1,然后更新i = cur + 1

Code实现

public List < Integer > partitionLabels(String S) {
    char[] arr = S.toCharArray();
    int[] local = new int[26];
    for (int i = 0; i < 26; i++) {
        local[i] = -1;
    }
    for (int i = 0; i < arr.length; i++) {
        local[arr[i] - 'a'] = i;
    }
    List < Integer > res = new ArrayList < > ();
    int i = 0;
    while (i < arr.length) {
        int cur = i;
        int bound = local[arr[cur] - 'a'];
        while (cur < bound) {
            cur++;
            bound = Math.max(bound, local[arr[cur] - 'a']);
        }
        res.add(cur - i + 1);
        i = cur + 1;
    }
    return res;
}

结果

Snipaste_2023-05-09_22-47-09.png

算法复杂度分析

  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(n)O(n)