剑指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) | 比较s1 和s2 两个字符串的大小,按照字典序进行比较。若s1 小于s2 返回负整数;若s1 等于s2 返回 0;若s1 大于s2 返回正整数。 |
strncmp(s1, s2, n) | 比较s1 和s2 中前n 个字符的大小,按照字典序比较,返回值规则同strcmp 。 |
strlen(s) | 计算字符串s 的长度,不包括结束符'\0' ,返回字符串中字符的个数。 |
strchr(s, c) | 在字符串s 中查找字符c 第一次出现的位置,若找到返回指向该字符的指针,若没找到返回nullptr 。 |
strrchr(s, c) | 在字符串s 中查找字符c 最后一次出现的位置,若找到返回指向该字符的指针,若没找到返回nullptr 。 |
strstr(s1, s2) | 在字符串s1 中查找字符串s2 第一次出现的位置,若找到返回指向s2 在s1 中起始位置的指针,若没找到返回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 位为中心的回文串数量为
。
时间复杂度 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.小结
变位词和回文是很有意思的文字游戏。如果两个字符串包含的字符及每个字符出现的次数都相同,只是字符出现的顺序不同,那么它们就是一组变位词。通常可以用一个哈希表来统计每个字符出现的次数,有了哈希表就很容易判断两个字符串是不是一组变位词。
回文是一类特殊的字符串。不管是从前往后还是从后往前读取其每一个字符,得到的内容都是一样的。通常可以用两个指针来判断一个字符串是不是回文,要么两个指针从字符串的两端开始向中间移动,要么两个指针从中间开始向两端移动。
相关文章:
剑指offer(专项突破)---字符串
总目录:剑指offer(专项突破)---目录-CSDN博客 1.字符串的基本知识 C语言中: 函数名功能描述strcpy(s1, s2)将字符串s2复制到字符串s1中,包括结束符\0,要求s1有足够空间容纳s2的内容。strncpy(s1, s2, n)…...
【springboot】 多数据源实现
文章目录 1. 引言:多数据源的必要性和应用场景**为什么需要多数据源?****应用场景** 2. Spring Boot中的数据源配置2.1 默认数据源配置简介2.2 如何在Spring Boot中配置多个数据源 3. 整合MyBatis与多数据源**配置MyBatis使用多数据源****Mapper接口的数…...

多模态COGMEN详解
✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨ 🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢,在这里我会分享我的知识和经验。&am…...
django 实战(python 3.x/django 3/sqlite)
要在 Python 3.x 环境中使用 Django 3.2 和 SQLite 创建一个新的 Django 项目,你可以按照以下步骤进行操作。这些步骤假设你已经安装了 Python 3.x 和 pip。 1. 设置虚拟环境 首先,建议为你的 Django 项目创建一个虚拟环境,以便隔离项目的依…...

图数据库 | 12、图数据库架构设计——高性能计算架构
在传统类型的数据库架构设计中,通常不会单独介绍计算架构,一切都围绕存储引擎展开,毕竟存储架构是基础,尤其是在传统的基于磁盘存储的数据库架构设计中。 类似地,在图数据库架构设计中,项目就围绕存储的方…...

Unity 利用Button 组件辅助Scroll View 滚动
实现 创建枚举类ScrollDir 以区分滚动方向。每组两个按钮负责同方向上左右/上下滚动。 Update 中实时获取Scroll View 滚动条当前位置。 if (dir.Equals(ScrollDir.vertical)) {posCurrent scroll.verticalNormalizedPosition; } else if (dir.Equals(ScrollDir.horizontal)…...
Ubuntu 安装Ansible ansible.cfg配置文件生成
安装后的ansible.cfg后的默认内容如下: rootlocalhost:/etc/ansible# cat ansible.cfg # Since Ansible 2.12 (core): # To generate an example config file (a "disabled" one with all default settings, commented out): # $ ansible-…...

使用PaddlePaddle实现线性回归模型
目录 编辑 引言 PaddlePaddle简介 线性回归模型的构建 1. 准备数据 2. 定义模型 3. 准备数据加载器 4. 定义损失函数和优化器 5. 训练模型 6. 评估模型 7. 预测 结论 引言 线性回归是统计学和机器学习中一个经典的算法,用于预测一个因变量࿰…...

MongoDB集群的介绍与搭建
MongoDB集群的介绍与搭建 一.MongoDB集群的介绍 注意:Mongodb是一个比较流行的NoSQL数据库,它的存储方式是文档式存储,并不是Key-Value形式; 1.1集群的优势和特性 MongoDB集群的优势主要体现在以下几个方面: (1)高…...

PhpStorm配置Laravel
本文是2024最新的通过phpstorm创建laravel项目 1.下载phpstorm 2.检查本电脑的环境phpcomposer 显示图标就是安装成功了,不会安装的百度自行安装 3.安装完后,自行创建一个空目录不要有中文,然后运行cmd 输入以下命令,即可创建…...

Solving the Makefile Missing Separator Stop Error in VSCode
1. 打开 Makefile 并转换缩进 步骤 1: 在 VSCode 中打开 Makefile 打开 VSCode。使用文件浏览器或 Ctrl O(在 Mac 上是 Cmd O)打开你的 Makefile。 步骤 2: 打开命令面板 按 Ctrl Shift P(在 Mac 上是 Cmd Shift P)&…...

MySQL大小写敏感、MySQL设置字段大小写敏感
文章目录 一、MySQL大小写敏感规则二、设置数据库及表名大小写敏感 2.1、查询库名及表名是否大小写敏感2.2、修改库名及表名大小写敏感 三、MySQL列名大小写不敏感四、lower_case_table_name与校对规则 4.1、验证校对规则影响大小写敏感4.1、验证校对规则影响排序 五、设置字段…...
项目搭建:guice,jdbc,maven
当然,以下是一个使用Guice、JDBC和Maven实现接口项目的具体例子。这个项目将展示如何创建一个简单的用户管理应用,包括用户信息的增删改查(CRUD)操作。 ### 1. Maven pom.xml 文件 首先确保你的pom.xml文件包含必要的依赖&#…...
第四届新生程序设计竞赛正式赛(C语言)
A: HNUCM的学习达人 SQ同学是HNUCM的学习达人,据说他每七天就能够看完一本书,每天看七分之一本书,而且他喜欢看完一本书之后再看另外一本。 现在请你编写一个程序,统计在指定天数中,SQ同学看完了多少本完整的书&#x…...
【分布式知识】Redis6.x新特性了解
文章目录 Redis6.x新特性1. 多线程I/O处理2. 改进的过期算法3. SSL/TLS支持4. ACL(访问控制列表)5. RESP3协议6. 客户端缓存7. 副本的无盘复制8. 其他改进 Redis配置详解1. 基础配置2. 安全配置3. 持久化配置4. 客户端与连接5. 性能与资源限制6. 其他配置…...

程序员需要具备哪些知识?
程序员需要掌握的知识广泛而深厚,这主要取决于具体从事的领域和技术方向。不过,有些核心知识是共通的,就像建房子的地基一样,下面来讲讲这些关键领域: 1. 编程语言: 无论你是搞前端、后端、移动开发还是嵌…...

实验四:MyBatis 的关联映射
目录: 一 、实验目的: 熟练掌握实体之间的各种映射关系。 二 、预习要求: 预习数据库原理中所讲过的一对一、一对多和多对多关系 三、实验内容: 1. 查询所有订单信息,关联查询下单用户信息(注意:因为一…...

【Leetcode】189.轮转数组
题目链接: 189.轮转数组 题目描述: 解题思路: 要想实现数组元素向右轮转k个位置,可是将数组三次反转来实现 以 nums [1,2,3,4,5,6,7], k 3 为例,最终要得到[5,6,7,1,2,3,4]: 第一次反转:将整个数组反转…...
【JavaSE】常见面试问题
1. 什么是 Java 中的多态? 多态是 Java 中面向对象的核心特性之一,指的是同一操作作用于不同类型的对象时表现出不同的行为。通过方法重载和方法重写实现。方法重载是同一方法名,根据参数不同做不同处理,属于编译时多态ÿ…...

【超详图文】多少样本量用 t分布 OR 正态分布
文章目录 相关教程相关文献预备知识Lindeberg-Lvy中心极限定理 t分布的来历实验不同分布不同抽样次数的总体分布不同自由度相同参数的t分布&正态分布 作者:小猪快跑 基础数学&计算数学,从事优化领域7年,主要研究方向:MIP求…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

SpringCloudGateway 自定义局部过滤器
场景: 将所有请求转化为同一路径请求(方便穿网配置)在请求头内标识原来路径,然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

如何更改默认 Crontab 编辑器 ?
在 Linux 领域中,crontab 是您可能经常遇到的一个术语。这个实用程序在类 unix 操作系统上可用,用于调度在预定义时间和间隔自动执行的任务。这对管理员和高级用户非常有益,允许他们自动执行各种系统任务。 编辑 Crontab 文件通常使用文本编…...