LeetCode 热题 100_划分字母区间(80_763_中等_C++)(贪心算法(求并集))

LeetCode 热题 100_划分字母区间(80_763)

题目描述:

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 "ababcc" 能够被分为 ["abab", "cc"],但类似 ["aba", "bcc"] 或 ["ab", "ab", "cc"] 的划分是非法的。

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

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

输入输出样例:

示例 1:
输入 :s = "ababcbacadefegdehijhklij"
输出 :[9,7,8]
解释

划分结果为 "ababcbaca"、"defegde"、"hijhklij" 。

每个字母最多出现在一个片段中。

像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。

示例 2:
输入 :s = "eccbbbbdec"
输出:[10]

提示:

1 <= s.length <= 500

s 仅由小写英文字母组成

题解:

解题思路:

思路一(贪心算法(求交集)):

1、题目要求同一字母最多出现在一个片段中。所以需求求出相交字母区间的并集。可以先遍历一遍字符串记录每个字母最后出现的位置。再从左往右遍历一遍,则必定先访问每个字母第一次出现的位置。将相交的字母区间求并集。

2、具体思路如下:

① 遍历一遍字符串记录每个字母最后出现的位置。

② 再从左往右遍历一遍,当碰到一个字母时判断当前字母最后出现的位置是否比之前字母出现的最远位置远,更新最远位置。

③ 当遍历到遍历过字母的最远位置时,记录区间中元素的个数,并重复 ② 和 ③ 过程,直到遍历完整个数组。

例: s="ababc"

记录字母出现的最远位置 last_position={a:2,b:3,c:4}

再从左往右遍历一遍:

① left=0,right=0。(left为当前区间的最左侧位置,right为当前区间的最远位置)

② i=0,字母a的最远位置为2,right=2

③ i=1,字母b的最远位置为3,right=3

④ i=2,字母a的最远位置为2,right=3

⑤ i=3,字母b的最远位置为3,right=3,i==right 记录区间元素个数 right-left+1=4。left=i+1=4

⑥ i=4,字母4的最远位置为4,right=4,i ==right记录区间元素个数 right-left+1=1。

3、复杂度分析:

① 时间复杂度:O(n),其中 n 是字符串的长度。需要遍历字符串两次。

② 空间复杂度:O(∣Σ∣),其中 Σ 是字符串中的字符集。这道题中,字符串只包含小写字母,因此 ∣Σ∣=26。

代码实现

代码实现(思路一(贪心算法(求并集)):
cpp 复制代码
class Solution {
public:
    vector<int> partitionLabels(string s) {
        // 用于存储每个字母最后出现的位置,初始化为-1
        vector<int> last_position(26, -1);  
        vector<int> ans;  // 存储结果,保存每个分割部分的长度
        
        // 记录每个字母最后出现的位置
        for (int i = 0; i < s.size(); i++) {
            // 'a' -> 0, 'b' -> 1, ..., 'z' -> 25
            last_position[s[i] - 'a'] = i;  
        }

        int left = 0, right = 0;  // left指向当前分区的起始位置,right指向当前分区的结束位置
        for (int i = 0; i < s.size(); i++) {
            // 更新当前字母的最后出现位置,right表示当前分区的结束位置
            right = max(right, last_position[s[i] - 'a']);  

            // 如果当前索引i已经到达该分区的最后位置,说明当前分区结束
            if (i == right) {
                // 记录当前分区的长度
                ans.push_back(right - left + 1);  
                left = i + 1;  // 更新下一个分区的起始位置
            }
        }

        // 返回所有分区的长度
        return ans;  
    }
};
以思路一为例进行调试
cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;

class Solution {
public:
    vector<int> partitionLabels(string s) {
        // 用于存储每个字母最后出现的位置,初始化为-1
        vector<int> last_position(26, -1);  
        vector<int> ans;  // 存储结果,保存每个分割部分的长度
        
        // 记录每个字母最后出现的位置
        for (int i = 0; i < s.size(); i++) {
            // 'a' -> 0, 'b' -> 1, ..., 'z' -> 25
            last_position[s[i] - 'a'] = i;  
        }

        int left = 0, right = 0;  // left指向当前分区的起始位置,right指向当前分区的结束位置
        for (int i = 0; i < s.size(); i++) {
            // 更新当前字母的最后出现位置,right表示当前分区的结束位置
            right = max(right, last_position[s[i] - 'a']);  

            // 如果当前索引i已经到达该分区的最后位置,说明当前分区结束
            if (i == right) {
                // 记录当前分区的长度
                ans.push_back(right - left + 1);  
                left = i + 1;  // 更新下一个分区的起始位置
            }
        }

        // 返回所有分区的长度
        return ans;  
    }
};

int main(int argc, char const *argv[])
{
    
    string str="ababcbacadefegdehijhklij";
    Solution s;
    vector<int> ans= s.partitionLabels(str);
    for (auto &i : ans){
        cout<<i<<" ";
    }
    return 0;
}

LeetCode 热题 100_划分字母区间(80_763)原题链接

欢迎大家和我沟通交流(✿◠‿◠)

相关推荐
草莓熊Lotso21 小时前
C++11 核心特性实战:列表初始化 + 右值引用与移动语义(附完整代码)
java·服务器·开发语言·汇编·c++·人工智能·经验分享
初夏睡觉1 天前
从0开始c++,但是重置版,第1篇(c++基本框架)
开发语言·c++
前端小白在前进1 天前
⭐力扣刷题:螺旋矩阵
算法·leetcode·矩阵
草莓熊Lotso1 天前
GCC/G++ 编译器完全指南:从编译流程到进阶用法(附实操案例)
linux·运维·服务器·网络·c++·人工智能·自动化
老赵聊算法、大模型备案1 天前
北京市生成式人工智能服务已备案信息公告(2025年12月11日)
人工智能·算法·安全·aigc
CoderYanger1 天前
C.滑动窗口-求子数组个数-越长越合法——2799. 统计完全子数组的数目
java·c语言·开发语言·数据结构·算法·leetcode·职场和发展
厕所博士1 天前
红黑树原理前置理解—— 2-3 树
算法·2-3树·红黑树原理理解前置
萌>__<新1 天前
力扣打卡每日一题————除自身外所有元素的乘积
数据结构·算法
xu_yule1 天前
算法基础—搜索(2)【记忆化搜索+BFS+01BFS+Floodfill]
数据结构·算法
s09071361 天前
Xilinx FPGA使用 FIR IP 核做匹配滤波时如何减少DSP使用量
算法·fpga开发·xilinx·ip core·fir滤波