2405. 子字符串的最优划分【双指针】【滑动窗口】
题目
给你一个字符串 s ,请你将该字符串划分成一个或多个 子字符串 ,并满足每个子字符串中的字符都是 唯一 的。也就是说,在单个子字符串中,字母的出现次数都不超过 一次 。
满足题目要求的情况下,返回 最少 需要划分多少个子字符串。
注意,划分后,原字符串中的每个字符都应该恰好属于一个子字符串。
难度:中等
提示:
1 <= s.length <= 105
s
仅由小写英文字母组成
题解
要求子字符串内的字符唯一,那么可以通过双指针确定范围,左指针确定起始位置,右指针确定尾部,遍历的时候维护一个表来确定是否字符重复,可以用set,但是题目只有小写字母,也可以自己通过一维数组自己维护一张表
Set版本-32 ms
class Solution {
public int partitionString(String s) {
Set<Character> set = new HashSet<>();
char[] chars = s.toCharArray();
List<String> list = new LinkedList<>();
int l = 0, r = 0;
while (r < chars.length) {
if (!set.contains(chars[r])) {
set.add(chars[r]);
} else {
list.add(s.substring(l, r));
l = r;
set.clear();
r--;
}
r++;
}
list.add(s.substring(l,r));
return list.size();
}
}
复杂度分析
- 时间复杂度:O(N)
- 空间复杂度:O(N)
数组表-8 ms
后面发现,需要统计次数,不需要具体的子字符串,所以直接统计就行
class Solution {
public int partitionString(String s) {
char[] chars = s.toCharArray();
int[] cnts = new int[26];
Arrays.fill(cnts, -1);
int res = 0;
int r = 0;
while (r < chars.length) {
if (cnts[chars[r] - 'a'] == -1) {
cnts[chars[r] - 'a']++;
} else {
res++;
Arrays.fill(cnts, -1);
r--;
}
r++;
}
return ++res;
}
}
复杂度分析
- 时间复杂度:O(N)
- 空间复杂度:O(C)