剑指offer(专项突破)---字符串

总目录:剑指offer(专项突破)---目录-CSDN博客


1.字符串的基本知识

C语言中: 

函数名功能描述
strcpy(s1, s2)将字符串s2复制到字符串s1中,包括结束符'\0',要求s1有足够空间容纳s2的内容。
strncpy(s1, s2, n)s2中最多n个字符复制到s1中。若s2的长度小于n,则s1中剩余部分用'\0'填充;若s2长度大于等于n,则s1不会以'\0'结尾(需手动添加)。
strcat(s1, s2)将字符串s2连接到字符串s1的末尾,s1要有足够空间容纳连接后的内容,会自动添加结束符'\0'
strncat(s1, s2, n)s2中最多n个字符连接到s1的末尾,然后添加'\0's1要预留足够空间。
strcmp(s1, s2)比较s1s2两个字符串的大小,按照字典序进行比较。若s1小于s2返回负整数;若s1等于s2返回 0;若s1大于s2返回正整数。
strncmp(s1, s2, n)比较s1s2中前n个字符的大小,按照字典序比较,返回值规则同strcmp
strlen(s)计算字符串s的长度,不包括结束符'\0',返回字符串中字符的个数。
strchr(s, c)在字符串s中查找字符c第一次出现的位置,若找到返回指向该字符的指针,若没找到返回nullptr
strrchr(s, c)在字符串s中查找字符c最后一次出现的位置,若找到返回指向该字符的指针,若没找到返回nullptr
strstr(s1, s2)在字符串s1中查找字符串s2第一次出现的位置,若找到返回指向s2s1中起始位置的指针,若没找到返回nullptr

C++中: 

函数名功能描述
size()返回字符串中字符的个数。
length()获取字符串的长度,即字符个数。
empty()判断字符串是否为空,为空返回true,否则返回false
clear()清空字符串内容,使其长度变为 0。
push_back(c)在字符串末尾添加一个字符c
pop_back()删除字符串末尾的一个字符。
compare(s2)比较当前字符串和s2的大小,按照字典序比较,返回值规则类似strcmp函数(小于返回负整数,等于返回 0,大于返回正整数)。
substr(pos, n)从索引pos位置开始提取连续的n个字符,若n省略,则提取从pos开始到末尾的所有字符,返回提取出来的子字符串。
find(s2, pos)从索引pos位置开始查找字符串s2第一次出现的位置,若找到返回位置索引,若没找到返回std::string::npos(一个特殊的表示未找到的值),若pos省略,则从开头查找。
rfind(s2, pos)从索引pos位置开始查找字符串s2最后一次出现的位置,返回值规则同find函数,若pos省略,则从末尾往前查找。
replace(pos, n, s2)将从索引pos开始的n个字符替换成字符串s2,若n省略,则替换从pos开始到末尾的所有字符。

2.双指针

第2章用两个指针来定位一个子数组,其中一个指针指向数组的第1个数字,另一个指针指向数组的最后一个数字,那么两个指针之间所包含的就是一个子数组。

如果将字符串看成一个由字符组成的数组,那么也可以用两个指针来定位一个子字符串,其中一个指针指向字符串的第1个字符,另一个指针指向字符串的最后一个字符,两个指针之间所包含的就是一个子字符串。

LCR 014. 字符串的排列 - 力扣(LeetCode)

题解:滑动窗口

数组模拟哈希表 cnt1 统计字符串 s1 中每个字符出现的次数,然后遍历字符串 s2,维护一个窗口大小为 m 的滑动窗口。

数组模拟哈希表 cnt2 统计窗口内每个字符出现的次数,当 cnt1=cnt2 时,说明窗口内的字符及其个数与字符串 s1 相同,返回 true 即可。

否则,遍历结束后,返回 false

时间复杂度 (m+n×∣Σ∣),空间复杂度 O(∣Σ∣)。其中 m 和 n 分别为字符串 s1 和 s2 的长度;而 ∣Σ∣ 为字符集的大小,本题中∣Σ∣=26。

class Solution 
{
public:bool checkInclusion(string s1, string s2) {int m = s1.size(), n = s2.size();if (m > n)return false;vector<int> cnt1(26), cnt2(26);for (int i = 0; i < m; ++i) {++cnt1[s1[i] - 'a'];++cnt2[s2[i] - 'a'];}if (cnt1 == cnt2)return true;for (int i = m; i < n; ++i) {++cnt2[s2[i] - 'a'];--cnt2[s2[i - m] - 'a'];if (cnt1 == cnt2)return true;}return false;}
};

优化:

每次加入和移除一个字符时,都需要比较两个哈希表,时间复杂度较高。我们可以维护一个变量 k,表示两个大小为 m 的字符串中,有多少种字符出现的个数不同。当 k=0 时,说明两个字符串中的字符个数相同。

时间复杂度 O(m+n+∣Σ∣),空间复杂度 O(∣Σ∣)。其中 m 和 n 分别为字符串 s1 和 s2 的长度;而 ∣Σ∣ 为字符集的大小,本题中 ∣Σ∣=26。

class Solution 
{
public:bool checkInclusion(string s1, string s2) {int m = s1.size(), n = s2.size();if (m > n)return false;vector<int> cnt(26);for (int i = 0; i < m; ++i) {--cnt[s1[i] - 'a'];++cnt[s2[i] - 'a'];}int k = 0;for (int x : cnt)if (x != 0)++ k;if (k == 0)return true;for (int i = m; i < n; ++i) {int a = s2[i - m] - 'a';int b = s2[i] - 'a';if (cnt[a] == 0)++ k;-- cnt[a];if (cnt[a] == 0)-- k;if (cnt[b] == 0)++ k;++ cnt[b];if (cnt[b] == 0)-- k;if (k == 0)return true;}return false;}
};

LCR 015. 找到字符串中所有字母异位词 - 力扣(LeetCode)

题解:滑动窗口

同LCR 014,优化方式也一样,添加一个差异计数器 

class Solution 
{
public:vector<int> findAnagrams(string s, string p) {int m = s.size();int n = p.size();vector<int> ans;if (m < n)return ans;vector<int> cnt1(26), cnt2(26);for (int i = 0; i < n; ++i) {++cnt1[s[i] - 'a'];++cnt2[p[i] - 'a'];}if (cnt1 == cnt2)ans.push_back(0);for (int i = n; i < m; ++i) {++cnt1[s[i] - 'a'];--cnt1[s[i - n] - 'a'];if (cnt1 == cnt2)ans.push_back(i - n + 1);}return ans;}
};

LCR 016. 无重复字符的最长子串 - 力扣(LeetCode)

题解:双指针 + 哈希表

遍历字符串 s,对于当前遍历到的字符 s[r],如果 s[r] 在 [l,r) 范围内有与 s[r] 相同的字符,我们就不断地向右移动指针 l,直到 ss[s[r]] 为 false,此时 [l,r) 中没有任何与 s[r] 相同的字符,我们就找到了以字符 s[r] 为结尾的最长子串。更新最长子串的长度,最终返回答案。

时间复杂度 O(n),空间复杂度 O(∣Σ∣),其中 n 为字符串 s 的长度,而 Σ 表示字符集,本题中字符集为所有 ASCII 码在 [0,128) 内的字符,即∣Σ∣=128。

class Solution 
{
public:int lengthOfLongestSubstring(string s) {bool ss[128] = {false};int ans = 0;for (int l = 0, r = 0; r < s.size(); ++ r) {while (ss[s[r]])ss[s[l++]] = false;ss[s[r]] = true;ans = max(ans, r - l + 1);}return ans;}
};

LCR 017. 最小覆盖子串 - 力扣(LeetCode)

题解:滑动窗口

  • 外层while循环 - 窗口扩张
    • while(r < s.size()):这个循环的条件是只要r指针还没遍历完整个字符串s,就持续向右移动r指针来扩展窗口,模拟窗口不断向右滑动去尝试包含t中所有字符的过程。
    • char i = s[r++];:每次获取r指针指向的字符,并将r指针后移一位来扩大窗口范围。
    • if(++curHash[i] <= baseHash[i]):将该字符在curHash数组中的出现次数加 1,然后判断加 1 后的次数是否小于等于其在baseHash数组中记录的t里该字符出现的次数。若成立,则将计数器count加 1。
  • 内层while循环 - 窗口收缩
    • while(count == t.size()):当count的值等于字符串t的长度时,意味着当前窗口已经包含了t中的所有字符,此时就进入内层循环来尝试收缩窗口,看能否找到更小的符合条件的窗口。
    • if(r-l < minLen):判断当前窗口的长度(r - l)是否小于已记录的最小窗口长度minLen,如果是,则更新k为当前窗口的起始位置l,更新minLen为当前窗口的长度,即找到了一个更短的包含t所有字符的窗口。
    • char o = s[l++];:从窗口的左边开始收缩,获取要移出窗口的字符,并将l指针后移一位。
    • if(curHash[o]-- <= baseHash[o]):将该字符在curHash数组中的出现次数减 1,然后判断减 1 后的次数是否小于等于其在baseHash数组中记录的t里该字符出现的次数。若成立,则将计数器count减 1。

两个指针 l 和 r 都是从最左端向最右端移动,且 l 的位置一定在r 的左边或重合。注意本题虽然在 while 循环里出现了一个 while 循环,但是因为内循环负责移动 l 指针,且 l 只会从左到右移动一次,因此总时间复杂度仍然是 O(n)。 

class Solution
{
public:string minWindow(string s, string t){//先统计字符情况int baseHash[128] = { 0 }, curHash[128] = { 0 };for(auto& ch : t){++baseHash[ch];}int k = 0, minLen = s.size() + 1;//k:记录窗口起始位置 minLen:记录最小窗口长度int l = 0, r = 0, count = 0;//外层循环:窗口扩张while(r < s.size()){char i = s[r++];if(++curHash[i] <= baseHash[i]){++count;}//内层循环:窗口收缩while(count == t.size()){if(r-l < minLen){k = l;minLen = r-l;}char o = s[l++];if(curHash[o]-- <= baseHash[o]){--count;}}}return minLen > s.size() ? "" : s.substr(k, minLen);}
};

3.回文字符串

LCR 018. 验证回文串 - 力扣(LeetCode)

题解:双指针

时间复杂度 O(n)。空间复杂度 O(1)。 

class Solution 
{
public:bool isPalindrome(string s) {int l = 0, r = s.size() - 1;while (l < r) {while (l < r && !isalnum(s[l]))++ l;while (l < r && !isalnum(s[r]))-- r;if (tolower(s[l]) != tolower(s[r]))return false;++ l;-- r;}return true;}
};

LCR 019. 验证回文串 II - 力扣(LeetCode)

题解:双指针 + 递归

时间复杂度 O(n)。空间复杂度 O(1)。 

class Solution 
{
public:bool validPalindrome(string s) {auto check = [&](int i, int j) {for (; i < j; ++i, --j)if (s[i] != s[j])return false;return true;};for (int i = 0, j = s.size() - 1; i < j; ++i, --j) if (s[i] != s[j])return check(i + 1, j) || check(i, j - 1);return true;}
};

LCR 020. 回文子串 - 力扣(LeetCode)

题解1:从中心向两侧扩展回文串

外层循环:遍历字符串每一位

内层循环:分别计算当前字符为中心点当前字符与下一位字符为中心点 

时间复杂度 O(n^2)。

class Solution 
{
public:int countSubstrings(string s) {int ans = 0;auto f = [&](int i, int j) -> int {int cnt = 0;for (; i >= 0 && j < s.size() && s[i] == s[j]; -- i, ++ j)++cnt;return cnt;};for (int i = 0; i < s.size(); ++ i)ans += f(i, i) + f(i, i + 1);return ans;}
};

题解2:Manacher 算法 

在 Manacher 算法的计算过程中,用 p[i]−1 表示以第 i 位为中心的最大回文长度,以第 i 位为中心的回文串数量为 \left \lceil \frac{p[i] - 1}{2} \right \rceil

时间复杂度 O(n),空间复杂度 O(n)。

class Solution 
{
public:int countSubstrings(string s) {int n = s.size();string t = "!#";for (const char &c: s) {t += c;t += '#';}n = t.size();t += '$';auto f = vector <int> (n);int mid = 0, rMax = 0, ans = 0;for (int i = 1; i < n; ++i) {// 初始化 f[i]f[i] = (i <= rMax) ? min(rMax - i + 1, f[2 * mid - i]) : 1;// 中心拓展while (t[i + f[i]] == t[i - f[i]]) ++f[i];if (i + f[i] - 1 > rMax) {mid = i;rMax = i + f[i] - 1;}// 当前贡献为 (f[i] - 1) / 2 上取整ans += (f[i] / 2);}return ans;}
};

4.小结

变位词和回文是很有意思的文字游戏。如果两个字符串包含的字符及每个字符出现的次数都相同,只是字符出现的顺序不同,那么它们就是一组变位词。通常可以用一个哈希表来统计每个字符出现的次数,有了哈希表就很容易判断两个字符串是不是一组变位词。

回文是一类特殊的字符串。不管是从前往后还是从后往前读取其每一个字符,得到的内容都是一样的。通常可以用两个指针来判断一个字符串是不是回文,要么两个指针从字符串的两端开始向中间移动,要么两个指针从中间开始向两端移动。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

915DEBUG-obsidianTemplater使用

Templater使用 tp函数不正常显示相应数据 模板使用方式不正确 <% tp.date.now("YYYY-MM-DD") %> 应该被放置在一个被Templater识别为模板的文件中&#xff0c;或者在你使用Templater的插入模板功能时输入。如果只是在一个普通的Markdown文件中直接输入这段代码…

OpenAI:AGI共5层,我们现在在第2层

迈向AGI顶峰的五层阶梯&#xff1a;我们正跨越的第二步 ©作者|潇潇 来源|神州问学 在2024年的OpenAI开发者日&#xff08;Dev Day&#xff09;上&#xff0c;我们见证了人工智能领域的一系列重大进展。OpenAI的CEO Sam Altman提出了一个关于通用人工智能&#xff08;AGI…

Python从入门到入狱

Python是从入门到入狱&#xff1f;这个充满调侃意味的说法在程序员圈子里流传甚广。表面看&#xff0c;它似乎是在嘲笑这门语言从简单易学到深陷麻烦的巨大反差&#xff0c;实际上却隐藏着很多值得深思的问题。要解读这个话题&#xff0c;得从Python的特点、使用场景以及潜在风…

AMEYA360 | 杭晶电子:晶振在AR/VR中的应用

晶振在AR/VR设备中扮演重要角色&#xff0c;为其核心电子系统提供稳定的时钟信号&#xff0c;确保设备的高性能运行。 以下是晶振在AR/VR应用中的具体作用&#xff1a; 01、图像处理与同步 1、晶振为图形处理单元(GPU)和显示芯片提供精准的时钟信号&#xff0c;支持高速图像渲染…

【前端】小程序实现预览pdf并导出

小程序实现预览pdf并导出 一、前言二、需要的wx api三、完整代码 一、前言 小程序没办法直接导出pdf或一些文档&#xff0c;只能借助api先将文件下载下来并打开&#xff0c;再让用户手动去保存。之前做“小程序当前页面截图转pdf导出”功能的时候&#xff0c;小程序好像也无法…

使用 postman 传递 binary 类型的图片到后端接口遇到的坑

使用 psotman 传 binary 类型图片报错&#xff1a; -2024-12-04 [http-nio-9090-exec-1] WARN org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver Resolved [org.springframework.http.converter.HttpMessageNotReadableException: Required r…

嵌入式系统应用-LVGL的应用-平衡球游戏 part1

平衡球游戏 part1 1 平衡球游戏的界面设计2 界面设计2.1 背景设计2.2 球的设计2.3 移动球的坐标2.4 用鼠标移动这个球2.5 增加边框规则2.6 效果图2.7 游戏失败重启游戏 3 为小球增加增加动画效果3.1 增加移动效果代码3.2 具体效果图片 平衡球游戏 part2 第二部分文章在这里 1 …

Linux 无界面模式下使用 selenium

文章目录 前言什么是无界面模式&#xff1f;具体步骤安装谷歌浏览器查看安装的谷歌浏览器的版本下载对应版本驱动并安装Python 测试代码 总结个人简介 前言 在 Linux 服务器上运行自动化测试或网页爬虫时&#xff0c;常常需要使用 Selenium 来驱动浏览器进行操作。然而&#x…

大数据新视界 -- Hive 数据湖集成与数据治理(下)(26 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

2.经典规划控制方法-深蓝学院

规划算法 关于规划算法可以参考我的博客 这里说明一下机械臂规划算法的特性以及规划算法的扩展 任务规划 - 路径规划 - 轨迹优化 过程&#xff1a;路径规划&#xff1a;笛卡尔空间通过IK求解得到关节空间&#xff08;构型空间c-space&#xff09;&#xff0c;然后通过关节插值…

基于Matlab计算机视觉的车道线识别与前车检测系统研究

随着自动驾驶技术的发展&#xff0c;车道线识别和前车检测成为智能驾驶系统中的核心技术之一。本实训报告围绕基于计算机视觉的车道线识别与前车检测系统展开&#xff0c;旨在通过处理交通视频数据&#xff0c;实时检测车辆所在车道及其与前车的相对位置&#xff0c;从而为车道…

Java Web 2 JS Vue快速入门

一 JS快速入门 1.什么是JavaScript&#xff1f; 页面交互&#xff1a; 页面交互是指用户与网页之间的互动过程。例如&#xff0c;当用户点击一个按钮&#xff0c;网页会做出相应的反应&#xff0c;如弹出一个对话框、加载新的内容或者改变页面的样式等&#xff1b;当用户在表…

OpenHarmony-4.GPIO驱动

GPIO 1.功能简介 GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出。GPIO又俗称为I/O口&#xff0c;I指的是输入(in&#xff09;&#xff0c;O指的是输出&#xff08;out&#xff09;。可以通过软件来控制其输入和输出&#xff0c;即I/O控制。通常&…

文本生成类(机器翻译)系统评估

在机器翻译任务中常用评价指标&#xff1a;BLEU、ROGUE、METEOR、PPL。 这些指标的缺点&#xff1a;只能反应模型输出是否类似于测试文本。 BLUE&#xff08;Bilingual Evaluation Understudy&#xff09;&#xff1a;是用于评估模型生成的句子(candidate)和实际句子(referen…

UG NX二次开发(Python)-UIStyler-选取点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1、前言2、设计一个UI界面3、创建长方体的代码4、需要引入的库5、测试验证1、前言 采用Python语言进行UG NX二次开发的资料比较少,我本来不是很认可采用Python进行二次开发的,但是近期有读者咨询…

鸿蒙 Next 可兼容运行 Android App,还支持出海 GMS?

最近 「出境易」和 「卓易通」 应该算是鸿蒙和 Android 开发圈“突如其来”的热门话题&#xff0c;而 「出境易」可能更高频一些&#xff0c;主要也是 Next 5.0 被大家发现刚上架了一个名为「出境易」的应用&#xff0c;通过这个 App 用户可以直接运行不兼容 Next 的 Android A…

请求响应:常见参数接收及封装(数组集合参数及日期参数)

数组参数 在前端页面的表单中&#xff0c;存在复选框元素&#xff0c;当提交表单到后端的时候&#xff0c;会将复选框中的全部内容提交到后端进行处理&#xff0c;由于复选框中往往存在很多数据&#xff0c;并且同复选框中数据名称相同&#xff0c;这样的请求参数叫做数组参数…

ASP.NET Core SignalR 入门

一、简介 &#x1f4e2; SignalR的主要功能是提供服务器和客户端之间的实时通信。当连接的客户端变得可用时&#xff0c;服务器可以立即向其推送内容&#xff0c;而不是等待客户端发起请求。这种功能特别适合需要实时更新数据的应用场景&#xff0c;如聊天应用、实时数据分析、…

介绍一下希尔排序法(c基础)

hi , I am 36 适合对象c语言初学者 希尔排序&#xff08;Shell Sort&#xff09;是一种改进的插入排序算法&#xff0c;它通过将原始数据分成多个子序列来改善插入排序在处理大规模无序数组时性能较差的情况。 基本原理 希尔排序的基本思想是先将整个待排序的记录序列分割成为…

Python知识分享第十九天-网络编程

网络编程 概述用来实现 网络互联 不同计算机上运行的程序间可以进行数据交互也叫Socket编程 套接字编程 三要素IP地址概述设备在网络中的唯一标识分类IPV4城域网13广域网22局域网31IPV6八字节 十六进制相关dos命令查看ipwindows: ipconfigmac和linux: ifconfig测试网络ping 域…