当前位置:网站首页>Leetcode(763)——划分字母区间
Leetcode(763)——划分字母区间
2022-06-26 20:43:00 【SmileGuy17】
Leetcode(763)——划分字母区间
题目
字符串 S 由小写字母组成。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。返回一个表示每个字符串片段的长度的列表。
示例:
输入:S = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”, “defegde”, “hijhklij”。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 的划分是错误的,因为划分的片段数较少。
提示:
- S的长度在 [ 1 , 500 ] [1, 500] [1,500]之间。
- S只包含小写字母 ‘a’ 到 ‘z’ 。
题解
关键:处理数组前可以统计一遍信息(频率、个数、第一次或最后一次的位置等)可以降低难度
方法一:贪心
思路
由于同一个字母只能出现在同一个片段,显然同一个字母的第一次出现的下标位置和最后一次出现的下标位置必须出现在同一个片段。因此需要遍历字符串,得到每个字母最后一次出现的下标位置。
在得到每个字母最后一次出现的下标位置之后,可以使用贪心的方法将字符串划分为尽可能多的片段,具体做法如下。
- 从左到右遍历字符串,遍历的同时维护当前片段的开始下标 start \textit{start} start 和结束下标 end \textit{end} end,初始时 start = end = 0 \textit{start}=\textit{end}=0 start=end=0。
- 对于每个访问到的字母 c c c,得到当前字母的最后一次出现的下标位置 end c \textit{end}_c endc,则当前片段的结束下标一定不会小于 end c \textit{end}_c endc,因此令 end = max ( end , end c ) \textit{end}=\max(\textit{end},\textit{end}_c) end=max(end,endc)。
- 当访问到下标 end \textit{end} end 时,当前片段访问结束,当前片段的下标范围是 [ start , end ] [\textit{start},\textit{end}] [start,end],长度为 end − start + 1 \textit{end}-\textit{start}+1 end−start+1,将当前片段的长度添加到返回值,然后令 start = end + 1 \textit{start}=\textit{end}+1 start=end+1,继续寻找下一个片段。
- 重复上述过程,直到遍历完字符串。
上述做法使用贪心的思想寻找每个片段可能的最小结束下标,因此可以保证每个片段的长度一定是符合要求的最短长度,如果取更短的片段,则一定会出现同一个字母出现在多个片段中的情况。由于每次取的片段都是符合要求的最短的片段,因此得到的片段数也是最多的。
由于每个片段访问结束的标志是访问到下标 end \textit{end} end,因此对于每个片段,可以保证当前片段中的每个字母都一定在当前片段中,不可能出现在其他片段,可以保证同一个字母只会出现在同一个片段。
或者
- 从头遍历字符串,并统计每一个字符最后出现的位置;
- 用一个变量 MaxPos 保存 目前已扫描字符的最后出现位置中的最大值 。然后再次从头遍历字符串,并更新 MaxPos 的值,如果找到当前下标和 MaxPos 相等了,则找到了分割点。
比如下图:先扫描 “ababc” 那么已扫描字符为 ‘a’ ‘b’ ‘c’,最后出现位置中的最大值,即 MaxPos 为8。当扫描到 “def” 时,已扫描字符为 ‘d’ ‘e’ ‘f’,MaxPos 为15。因为字符 ‘a’ ‘b’ ‘c’ 已经是上一个区间的字符了,被分割开了。
代码实现
Leetcode 官方题解:
class Solution {
public:
vector<int> partitionLabels(string s) {
vector<int> res;
int last[26];
int n = s.size();
for (int i = 0; i < n; i++)
last[s[i]-'a'] = i; //记录每个字母在s中的最后位置
int start = 0, end = 0;
for (int i = 0; i < n; i++){
end = max(end, last[s[i]-'a']);
if (end == i){
res.push_back(end - start + 1);
start = end + 1;
}
}
return res;
}
};
我自己的:
class Solution {
public:
vector<int> partitionLabels(string s) {
// 总问题:找出最多的区间,满足同一字母只会出现在同一个区间
// 将同一字母的起始点和终点看成一个区间的左端点和右端点
// 该问题转换为:将重叠区间看成同一个区间,获取最多的区间个数
unordered_map<char, int> letter;
vector<vector<int>> section;
int size = s.size();
for(int n = 0; n < size; n++){
if(letter.count(s[n]) == 0){
section.push_back({
n, n});
letter.emplace(s[n], section.size()-1);
}else section[letter[s[n]]][1] = n;
}
// for(auto& it: letter) cout << it.first << " :" << section[it.second][0] << " " << section[it.second][1] << endl;
// 不需要按左端点进行升序排序,因为之前循环时保存就是以左端点从0到size-1保存的
vector<int> ans;
vector<vector<int>> tmp;
size = section.size();
for(int n = 0; n < size; n++){
// 开始时或新区间与上一个区间不重叠,则创建新区间,并计算前一个区间的长度
if(tmp.empty() || section[n][0] >= (*tmp.rbegin())[1]){
if(!tmp.empty()) ans.push_back((*tmp.rbegin())[1] - (*tmp.rbegin())[0] + 1);
tmp.push_back({
section[n][0], section[n][1]});
}else (*tmp.rbegin())[1] = max((*tmp.rbegin())[1], section[n][1]);
if(n == size-1) ans.push_back((*tmp.rbegin())[1] - (*tmp.rbegin())[0] + 1);
}
return ans;
}
};
复杂度分析
时间复杂度: O ( n ) O(n) O(n),其中 nn 是字符串的长度。需要遍历字符串两次,第一次遍历时记录每个字母最后一次出现的下标位置,第二次遍历时进行字符串的划分。
空间复杂度: O ( ∣ Σ ∣ ) O(∣\Sigma∣) O(∣Σ∣),其中 Σ \Sigma Σ 是字符串中的字符集。这道题中,字符串只包含小写字母,因此 ∣ Σ ∣ = 26 |\Sigma|=26 ∣Σ∣=26。
边栏推荐
- Feitian +cipu body brings more imagination to the metauniverse
- windows系统下怎么安装mysql8.0数据库?(图文教程)
- Fixed length memory pool
- 【最详细】最新最全Redis面试大全(42道)
- [most detailed] the latest and complete redis interview (70)
- Super VRT
- Arrête d'être un bébé géant.
- Introduction to single chip microcomputer one-on-one learning strategy, independent development program immediately after reading
- 0基础学c语言(3)
- Detailed explanation of retrospective thinking
猜你喜欢

Student information management system based on SSH Framework

Muke 8. Service fault tolerance Sentinel

【protobuf 】protobuf 升级后带来的一些坑

The source code that everyone can understand (I) the overall architecture of ahooks

Leetcode question brushing: String 05 (Sword finger offer 58 - ii. left rotation string)

动态规划111

MySQL - table creation and management

Disruptor local thread queue_ Use transprocessor processor and workpool to compare consumption - Notes on inter thread communication 005

分布式ID生成系统

windows系统下怎么安装mysql8.0数据库?(图文教程)
随机推荐
Détails de l'annotation des ressources sentinelles
Muke 11. User authentication and authorization of microservices
C language file cursor fseek
Twenty five of offer - all paths with a certain value in the binary tree
swagger:如何生成漂亮的静态文档说明页
lotus configurations
阿里云个人镜像仓库日常基本使用
Can I open an account online? Is it safe?
leetcode刷题:字符串05(剑指 Offer 58 - II. 左旋转字符串)
Leetcode question brushing: String 06 (implement strstr())
C language simple login
慕课8、服务容错-Sentinel
宝藏又小众的覆盖物PBR多通道贴图素材网站分享
论数据库的传统与未来之争之溯源溯本----AWS系列专栏
leetcode刷题:字符串01(反转字符串)
飞天+CIPU体为元宇宙带来更大想象空间
[most detailed] latest and complete redis interview (42 tracks)
[serialization] how to master the core technology of opengauss database? Secret 5: master database security (6)
Feitian +cipu body brings more imagination to the metauniverse
leetcode刷题:字符串04(颠倒字符串中的单词)