763. 划分字母区间(力扣LeetCode)

763. 划分字母区间

题目描述

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。

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

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

示例 1:

输入:s = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”、“defegde”、“hijhklij” 。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 这样的划分是错误的,因为划分的片段数较少。

示例 2:

输入:s = “eccbbbbdec”
输出:[10]

提示:

  • 1 <= s.length <= 500
  • s 仅由小写英文字母组成

贪心算法

一想到分割字符串就想到了回溯,但本题其实不用回溯去暴力搜索。

题目要求同一字母最多出现在一个片段中,那么如何把同一个字母的都圈在同一个区间里呢?

如果没有接触过这种题目的话,还挺有难度的。

在遍历的过程中相当于是要找每一个字母的边界,如果找到之前遍历过的所有字母的最远边界,说明这个边界就是分割点了。此时前面出现过所有字母,最远也就到这个边界了。

可以分为如下两步:

  • 统计每一个字符最后出现的位置
  • 从头遍历字符,并更新字符的最远出现下标,如果找到字符最远出现位置下标和当前下标相等了,则找到了分割点

如图:
在这里插入图片描述

rfind函数

以下是对于给出的代码的详细注释,解释了它是如何解决问题的:

#include <vector>
#include <string>
using namespace std;

class Solution {
public:
    vector<int> partitionLabels(string s) {
        vector<int> res; // 用于存储每个片段的长度
        int end=0; // 记录当前遍历到的所有字符中,最远的出现位置
        int cnt=0; // 当前片段的长度计数器

        // 遍历给定的字符串
        for(int i=0; i<s.size(); i++) {
            cnt++; // 每遍历一个字符,当前片段的长度加1
            // 更新当前片段中字符最远出现位置的最大值
            // s.rfind(s[i]) 返回字符s[i]最后一次出现的位置
            // 因为s.rfind的返回类型为size_t,可能与int类型的end不匹配,所以要进行类型转换
            end = max(end, (int)s.rfind(s[i]));

            // 如果当前字符是当前片段中最远出现位置的字符,
            // 则说明到目前为止的这一段可以独立为一个片段
            if (end == i) {
                // 将当前片段的长度添加到结果列表中
                res.push_back(cnt);

                // 重置计数器为下一个片段做准备
                cnt = 0;
            }
        }
        // 返回结果列表,包含了每个片段的长度
        return res;
    }
};

这段代码核心在于,通过遍历字符串,并使用end变量跟踪当前遍历到的所有字符中最远的出现位置。每当end与当前遍历的索引i相等时,说明到目前为止的这一段字符串可以划分为一个片段,因为它包含了一组字符,这些字符之后不再出现。然后,记录下这个片段的长度,并重置计数器和end变量,以便计算下一个片段的长度。最终,所有片段的长度被添加到结果列表中并返回。

易错:rfind函数返回值问题

在我没进行强制类型转换时,代码报错

Line 10: Char 17: error: no matching function for call to 'max'
   10 |             end=max(end,s.rfind(s[i]));
      |                 ^~~
/usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/algorithmfwd.h:407:5: note: candidate template ignored: deduced conflicting types for parameter '_Tp' ('int' vs. 'size_type' (aka 'unsigned long'))
  398 |     max(const _Tp&, const _Tp&);
      |     ^
/usr/bin/../lib/gcc/x86_64-linux-gnu/11/../../../../include/c++/11/bits/stl_algo.h:3467:5: note: candidate template ignored: could not match 'initializer_list<_Tp>' against 'int'
 3458 |     max(initializer_list<_Tp> __l, _Compare __comp)
      |     ^

这个错误信息表明max函数无法匹配到合适的重载版本,原因是传递给max的两个参数ends.rfind(s[i])具有不同的类型。在C++中,rfind返回的是size_type类型,这通常是一个无符号整数类型(比如unsigned long),而end被定义为int类型,是一个有符号整数。

在C++标准库中,max要求两个参数具有相同的类型,因为它需要能够比较这两个参数并返回其中较大的一个。当你尝试使用两个不同类型的参数调用max时,编译器无法决定应该使用哪个类型来比较,因此会报错。

解决这个问题的一种方法是,确保max的两个参数类型一致。如果你确认end变量不会存储超过int类型能表示的范围的值,可以通过强制类型转换将rfind的返回值转换为int类型,如下所示:

end = max(end, (int)s.rfind(s[i]));

哈希表

这段代码是一个解决上述问题的C++实现。我将在代码的每一部分提供详细的注释来解释它的作用。

#include <vector>
#include <string>

using namespace std;

class Solution {
public:
    vector<int> partitionLabels(string s) {
        vector<int> res; // 创建一个空的整数向量来存储最后的片段长度结果

        // 数组用于记录每个字符最后出现的索引位置
        // 因为输入字符串只包含小写字母,所以只需要大小为26的数组
        int index[26];

        // 第一个循环遍历字符串s的每个字符
        for(int i = 0; i < s.size(); i++)
            // 计算字符到'a'的距离,作为数组索引,并更新这个字符对应的最后出现位置
            // 'a'的ASCII码将被用作基准点,所以任何字符都可以通过减去'a'得到一个0到25的索引值
            index[s[i] - 'a'] = i;

        // 初始化用于追踪当前片段最右端字符的索引
        int right = 0;
        int cnt = 0; // 计数器,用于记录当前片段的长度

        // 第二个循环同样遍历字符串的每个字符
        for(int i = 0; i < s.size(); i++) {
            // 增加当前片段的计数器
            cnt++;
            // 通过字符索引,找到当前片段最右端字符的索引,与当前的`right`比较,取较大者
            // 这样可以确保当前片段包含所有已遍历字符的最后出现
            right = max(right, index[s[i] - 'a']);

            // 如果当前字符的位置i与`right`相等,说明当前片段不会再扩展了
            if(right == i) {
                // 把当前片段的长度加入到结果集
                res.push_back(cnt);
                // 重置计数器,为下一个片段准备
                cnt = 0;
            }
        }
        // 返回分段的长度数组
        return res;
    }
};

该代码分为两个主要部分:第一部分遍历字符串,记录每个字符最后出现的位置;第二部分再次遍历字符串,根据每个字符的最后出现位置,确定每个片段的边界并记录其长度。

这种方法能够确保每个字符仅出现在一个片段中,且得到的片段数目是最大化的。最终,我们得到一个数组,记录了根据给定规则得到的每个片段的长度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/496127.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pip wheel直接为离线环境打包需要的python包

很多情况下&#xff0c;需要离线安装python库&#xff0c;直接下载所需的库包时&#xff0c;可能又要求更新或安装相关的依赖包&#xff08;这就非常麻烦了&#xff09;&#xff0c;所以推荐一条命令一步到位&#xff0c;命令如下&#xff1a; pip wheel -r requirements.txt …

设计模式-设配器模式

目录 &#x1f38a;1.适配器模式介绍 &#x1f383;2.适配器类型 &#x1f38f;3.接口适配器 &#x1f390;4.类的适配器 &#x1f38e;5.优缺点 1.适配器模式介绍 适配器模式&#xff08;Adapter Pattern&#xff09;是作为两个不兼容的接口之间的桥梁。这种类型的设…

什么?想让视频号小店领先同行,竟然这么简单!

大家好&#xff0c;我是电商小布。 视频号小店从推出到现在&#xff0c;逐渐也是被越来越多的人所熟知了。 虽然说当前市场内部的商家数量并不多&#xff0c;竞争力不大。 但是在入驻之后想要领先同行商家&#xff0c;产生更好的店铺数据&#xff0c;该怎么来做呢&#xff1…

学习JavaEE的日子 Day29 yield,join,线程的中断,守护线程,线程局部变量共享,线程生命周期

Day29 多线程 12. 线程的礼让 Thread.yield(); 理解&#xff1a;此方法为静态方法&#xff0c;此方法写在哪个线程中&#xff0c;哪个线程就礼让 注意&#xff1a;所谓的礼让是指当前线程退出CPU资源&#xff0c;并转到就绪状态&#xff0c;接着再抢 需求&#xff1a;创建两个…

多叉树题目:N 叉树的后序遍历

文章目录 题目标题和出处难度题目描述要求示例数据范围进阶 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 解法三思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;N 叉树的后序遍历 出处&#xff1a;590. N 叉树的后序遍历 难度 3 级 题目…

Android笔记(三十):PorterDuffXfermode实现旋转进度View

背景 核心原理是使用PorterDuffXfermode Path来绘制进度&#xff0c;并实现圆角 效果图 Android笔记(三十)效果演示 进度条绘制步骤 将ImageView矩形七个点的坐标存储起来&#xff08;configNodes&#xff09; 他们对应着7个不同的刻度&#xff0c;每个刻度的值 i * &#…

Unity | 射线检测及EventSystem总结

目录 一、知识概述 1.Input.mousePosition 2.Camera.ScreenToWorldPoint 3.Camera.ScreenPointToRay 4.Physics2D.Raycast 二、射线相关 1.3D&#xff08;包括UI&#xff09;、射线与ScreenPointToRay 2.3D&#xff08;包括UI&#xff09;、射线与ScreenToWorldPoint …

计算机基础,挑战全网最全解析

1.什么是计算机&#xff1f; 2.冯诺依曼结构 3.进制 4.摩尔斯码和布莱叶盲文 摩尔斯码 布莱叶盲文

如何使用群晖WebDAV实现固定公网地址同步Zotero文献管理器

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

蓝桥杯嵌入式学习笔记(6):IIC程序设计

目录 前言 1. IIC基本原理 2. 电路原理 3. 代码编程 3.1 预备工作 3.2 AT24C02写读功能编写 3.2.1 AT24C02写操作实现 3.2.2 AT24C02读操作实现 3.3 MCP4017写读功能编写 3.3.1 MCP4017写操作实现 3.3.2 MCP4017读操作实现 3.4 main.c编写 3.4.1 头文件引用 3.4.…

基于javaweb(springboot+mybatis)网上酒类商城项目设计和实现以及文档报告

基于javaweb(springbootmybatis)网上酒类商城项目设计和实现以及文档报告 博主介绍&#xff1a;多年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 央顺技术团队 Java毕设项目精品实战案例《1000套》 欢迎点赞…

Redis数据类型介绍和使用

数据类型 String&#xff08;字符串&#xff09;&#xff1a;最基本的数据类型&#xff0c;可以存储任何类型的数据&#xff0c;如文本、数字等。Hash&#xff08;哈希&#xff09;&#xff1a;用于存储字段-值对的散列集合&#xff0c;适用于存储对象。List&#xff08;列表&…

鱼哥赠书活动第14期:看完这本《数字化运维》掌握数字化运维方法,构建数字化运维体系

鱼哥赠书活动第14期&#xff1a;看完这本《数字化运维》掌握数字化运维方法&#xff0c;构建数字化运维体系 主要内容&#xff1a;读者对象&#xff1a;赠书抽奖规则:往期赠书福利&#xff1a; 数字化转型已经成为大势所趋&#xff0c;各行各业正朝着数字化方向转型&#xff0c…

如何在群晖NAS搭建bitwarden密码管理软件并实现无公网IP远程访问

前言 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊如何在群晖NAS搭建bitwarden密码管理软件并实现无公网IP远程访问&#xff0c;希望大家能觉得实用&#xff01; 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&am…

【数据结构】链表习题之环形链表的约瑟夫问题

&#x1f451;个人主页&#xff1a;啊Q闻 &#x1f387;收录专栏&#xff1a;《数据结构》 &#x1f389;道阻且长&#xff0c;行则将至 前言 今天这道题目时牛客上的题目&#xff0c;名为环形链表的约瑟夫问题&#xff0c;很有趣的的一道题目 环形链表的约瑟…

申请免费域名证书

目录 背景&#xff1a; 域名证书是什么&#xff1a; 域名证书有哪些&#xff1a; 部署域名证书有什么用&#xff1a; 免费的域名证书在哪里申请&#xff1a; 背景&#xff1a; 域名是一个IP地址上的“面具” 。一个域名的目的是便于记忆和沟通的一组服务器的地址(网站&…

OpenHarmony开发知识点记录之ABI

OpenHarmony系统支持丰富的设备形态&#xff0c;支持多种架构指令集&#xff0c;支持多种操作系统内核&#xff1b;为了应用在各种OpenHarmony设备上的兼容性&#xff0c;本文定义了"OHOS" ABI&#xff08;Application Binary Interface&#xff09;的基础标准&#…

路由协议RIP(悄悄话)

实验要求&#xff1a;总部和两个分支&#xff0c;拓扑如下图&#xff0c;利用rip路由协议使得各个pc设备可以通信 RIP理解&#xff1a;相邻路由定期交换内部路由协议&#xff0c;最后达到稳定状态&#xff0c;如果发生网络发生变化&#xff0c;重复交换路由步骤直到稳定状态&a…

LinkedIn 互联网架构扩展简史

LinkedIn成立于 2003 年&#xff0c;其目标是连接到您的网络以获得更好的工作机会。第一周只有 2,700 名会员。时间快进了很多年&#xff0c;LinkedIn 的产品组合、会员基础和服务器负载都取得了巨大的增长。 如今&#xff0c;LinkedIn 在全球运营&#xff0c;拥有超过 3.5 亿会…

研华工控机610L学习笔记2:visualstudio与第一个C#程序

今日继续学习工控机 C# 编程相关知识&#xff1a; 这篇结束后我将先进行一段时间的C#的学习研究&#xff0c;并写一些C#的笔记 后续再更新工控机编程设计相关 目录 1、安装visualstudio&#xff1a; 2、创建第一个C#程序&#xff1a; 3、寻找C#解决方案源文件&#xff1a; …