当前位置:网站首页>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。
边栏推荐
- Jz-062- the k-th node of binary search tree
- [Shandong University] information sharing for the first and second examinations of postgraduate entrance examination
- 清华大学就光刻机发声,ASML立马加紧向中国出口光刻机
- Sword finger offer II 091 Paint the house
- MySQL中存储过程的详细详解
- How to install mysql8.0 database under Windows system? (Graphic tutorial)
- On the origin of the dispute between the tradition and the future of database -- AWS series column
- C language file cursor fseek
- GameFi 活跃用户、交易量、融资额、新项目持续性下滑,Axie、StepN 能摆脱死亡螺旋吗?链游路在何方?
- Record a redis large key troubleshooting
猜你喜欢
![[Bayesian classification 4] Bayesian network](/img/5b/348e00c920028e33ca457196586d36.png)
[Bayesian classification 4] Bayesian network

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

Yonghui released the data of Lantern Festival: the sales of Tangyuan increased significantly, and several people's livelihood products increased by more than 150%

Redis + Guava 本地缓存 API 组合,性能炸裂!

Super VRT

【 protobuf 】 quelques puits causés par la mise à niveau de protobuf
Mongodb implements creating and deleting databases, creating and deleting tables (sets), and adding, deleting, modifying, and querying data

慕课8、服务容错-Sentinel
![[Shandong University] information sharing for the first and second examinations of postgraduate entrance examination](/img/f9/68b5b5ce21f4f851439fa061b477c9.jpg)
[Shandong University] information sharing for the first and second examinations of postgraduate entrance examination

动态规划111
随机推荐
Is there any risk in opening a mobile stock registration account? Is it safe?
Bonne Recommandation: développer des outils de sécurité pour les terminaux mobiles
【protobuf 】protobuf 昇級後帶來的一些坑
浏览器的垃圾回收机制
不要做巨嬰了
The two files are merged into a third file.
Browser event loop
【连载】说透运维监控系统01-监控系统概述
Dynamic parameter association using postman
leetcode刷题:字符串05(剑指 Offer 58 - II. 左旋转字符串)
leetcode刷题:哈希表08 (四数之和)
StringUtils判断字符串是否为空
Muke 11. User authentication and authorization of microservices
SentinelResource注解詳解
浏览器事件循环
[Bayesian classification 3] semi naive Bayesian classifier
【最详细】最新最全Redis面试大全(70道)
Idea error: process terminated
开发者调查:Rust/PostgreSQL 最受喜爱,PHP 薪水偏低
Daily basic use of alicloud personal image warehouse