Easy
题目描述
在一个由小写字母构成的字符串 s 中,包含由同一字符组成的连续段。
例如,在字符串 s = “abbxxxxzyy” 中,就含有 “a”, “bb”, “xxxx”, “z” 和 “yy” 这样的一些分组。
分组可以用区间 [start, end] 表示,其中 start 和 end 分别表示该分组的起始和终止位置的下标。上例中的 “xxxx” 分组用区间表示为 [3,6]。
我们称所有包含大于或等于三个连续字符的分组为较大分组。
找到每一个较大分组的区间,按起始位置下标递增顺序排序后,返回结果。
示例 1:
输入:s = "abbxxxxzzy"
输出:[[3,6]]
解释:"xxxx" 是一个起始位置下标为 3,终止位置下标为 6 的较大分组。
示例 2:
输入:s = "abc"
输出:[]
解释:我们有 "a", "b", "c" 这样的分组,但都不是较大分组。
示例 3:
输入:s = "abcdddeeeeaabbbcd"
输出:[[3,5],[6,9],[12,14]]
解释:较大分组为 "ddd", "eeee" 和 "bbb"。
提示:
- 1 <= s.length <= 1000
- s 仅含小写英文字母
解题思路
解题思路
这道题目要求找到字符串中长度大于等于3的连续相同字符分组的位置区间。
双指针法(推荐解法)
使用双指针遍历字符串,时间复杂度O(n),空间复杂度O(1)(不计输出空间):
- 初始化两个指针:
i作为分组的起始位置,j用于寻找分组的结束位置 - 对于每个位置
i,向右移动j直到遇到不同字符 - 计算当前分组长度
j - i,如果长度 >= 3,则将区间[i, j-1]加入结果 - 更新
i = j,继续处理下一个分组
实现要点
- 内层while循环用于找到当前分组的结束位置
- 注意区间是闭区间
[start, end],所以结束位置是j-1 - 由于按顺序遍历,结果自然按起始位置递增排序
这种方法简洁高效,每个字符只被访问一次,是最优解法。
代码实现
class Solution {
public:
vector<vector<int>> largeGroupPositions(string s) {
vector<vector<int>> result;
int n = s.length();
int i = 0;
while (i < n) {
int j = i;
while (j < n && s[j] == s[i]) {
j++;
}
if (j - i >= 3) {
result.push_back({i, j - 1});
}
i = j;
}
return result;
}
};
class Solution:
def largeGroupPositions(self, s: str) -> List[List[int]]:
result = []
n = len(s)
i = 0
while i < n:
j = i
while j < n and s[j] == s[i]:
j += 1
if j - i >= 3:
result.append([i, j - 1])
i = j
return result
public class Solution {
public IList<IList<int>> LargeGroupPositions(string s) {
var result = new List<IList<int>>();
int n = s.Length;
int i = 0;
while (i < n) {
int j = i;
while (j < n && s[j] == s[i]) {
j++;
}
if (j - i >= 3) {
result.Add(new List<int> { i, j - 1 });
}
i = j;
}
return result;
}
}
/**
* @param {string} s
* @return {number[][]}
*/
var largeGroupPositions = function(s) {
const result = [];
const n = s.length;
let i = 0;
while (i < n) {
let j = i;
while (j < n && s[j]
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(n) - 每个字符只被访问一次 |
| 空间复杂度 | O(1) - 只使用常数额外空间(不计输出空间) |