【算法刷题】字符串题型及方法归纳

字符串特点

由若干字符(char)构成的有限序列,相当于是字符数组。在C语言中,字符串通过\0来判定结尾标志,而在C++中,会提供一个string类,通过string.size()判定是否到达末尾。
C语言

char a[5] = "abc";
for(int i = 0; a[i] != '\0'; i++)
	// Operation

C++

string a = "abc";	// 定义空时,a = ""
for(int i = 0; i < a.size(); i++)
	// Operation

注意:每次获取一个字符要判定时,字符外面要用 ’ ’ 括住而不是 " " 括住来与字符判定。

双指针相关题型

  1. 左右指针替换元素
    344. 反转字符串
    库函数reverse():是左闭右开,本题通过左右指针,实现了一个左闭右闭的反转函数

  2. 一个字符被多个字符替代,双指针从后往前填充
    76、【字符串】剑指 Offer ——05. 替换空格(C++版本)
    设置两个独立双指针,由于为一个字符被多个字符替代,可以从后往前填充,每次都移除足够的位置,原字符串末尾位置和新字符串末尾位置各设置一个指针,一次遍历即可完成填充。

  3. 快慢指针填充元素
    77、【字符串】leetcode ——151. 反转字符串中的单词(C++版本)
    (1)预处理:对于空格的处理,采用和 203. 移除链表元素 同样的快慢双指针思路,按照首尾无空格,每个单词间有一个空格进行填充。
    (2)完成预处理后,先对整体逆置,再对每个单词进行逆置。

字符串旋转题型

  1. 左右指针实现旋转
    344. 反转字符串
    库函数reverse():是左闭右开,本题通过左右指针,实现了一个左闭右闭的反转函数

  2. 旋转+2k为单位移动+小于等于k反转判定
    75、【字符串】leetcode——541. 反转字符串 II(C++版本)
    本题是在反转字符串的基础上,每次以2k为单位进行移动,旋转前k个子串。当移动到后续字符串长度小于等于k时,对其整体反转。

  3. 先整体逆置,再部分逆置,实现以区域内部元素不旋转,区域与区域之间旋转
    77、【字符串】leetcode ——151. 反转字符串中的单词(C++版本)
    (1)预处理:对于空格的处理,采用和 203. 移除链表元素 同样的快慢双指针思路,按照首尾无空格,每个单词间有一个空格进行填充。
    (2)完成预处理后,先对整体逆置,再对每个单词进行逆置。

  4. 先部分逆置,再整体逆置,实现区域内部元素不旋转,区域间进行了移动
    78、【字符串】剑指 Offer ——58 - II. 左旋转字符串(C++版本)
    方法一:使用substr()函数,先截取后面的字符,再截取前面的字符进行拼接。
    方法二:对前面部分和后面部分分别逆置,然后再整体逆置。

KMP题型

KMP理论和实现部分:41、【匹配算法】KMP字符串匹配算法(C/C++版)

KMP算法实现
(1)next不减去一

//const int M = 1e5 + 10, N = 1e6 + 10;
// int next[M]; 
// char p[M]; 		// 模式串
// char s[N];		// 目标串
// int m;			// 模式串的长度
void getNext(int next[], char p[], int m){
	// 初始化
	next[0] = 0;
	// j为前缀的末尾, i为后缀的末尾。前缀是除最后一个字符,后缀是除第一个字符。
	for(int i = 1, j = 0; i < m; i++){
		// 每次基于之前已记录的最长相等前后缀的基础上进行对比
		// 处理前后缀不相同的情况,退回到之前最长的相等前后缀,基于此再进行延伸对比
		while(j > 0 && p[i] != p[j])	j = next[j - 1];		// 存户的长度相对于下标少一个数,跳转时候根据next[j-1]跳转
		// 处理前后缀相同的情况
		if(p[i] == p[j])			j++;
		// 在前缀表做记录
		next[i] = j;		// 存储最长相等前后缀的长度,而长度相对于下标少一个数,跳转时候根据next[i-1]跳转
	}
}

void matching(int next[], char p[], int m, char s[], int n) {

int next[M];
getNext(next, p, m);
for(int i = 0, j = 0; i < n; i++){
	// 每次基于已有最长公共前后缀匹配,处理不相同情况
    while(j && s[i] != p[j])    j = next[j - 1];
    // 处理相同情况
    if(s[i] == p[j])            j++;
    // 处理匹配成功情况
    if(j == m)
    	// 输出目标串中所有与模式串匹配的起始位置下标
        printf("%d ", i - m + 1);
        // 为保证最长子序列匹配,因此从后向前进行匹配,将j指向前一个元素的next中的值
    }
}

(2)next减去一

//const int M = 1e5 + 10, N = 1e6 + 10;
// int next[M]; 
// char p[M]; 		// 模式串
// char s[N];		// 目标串
// int m;			// 模式串的长度
void getNext(int next[], char p[], int m){
	// 初始化
	next[0] = -1;
	// j为前缀的末尾, i为后缀的末尾。前缀是除最后一个字符,后缀是除第一个字符。
	for(int i = 1, j = -1; i < m; i++){
		// 每次基于已有最长公共前后缀匹配,处理不相同情况
		while(j >= 0 && p[i] != p[j + 1])	j = next[j]; 	// next中-1的好处是,跳转时候直接根据当前位置所记录的值跳转
		// 处理前后缀相同的情况
		if(p[i] == p[j + 1])			j++;
		// 在前缀表做记录
		next[i] = j;		// 因初始化为-1,因此存储的值为最长相等前后缀的长度减去一
	}
}

void matching(int next[], char p[], int m, char s[], int n) {

int next[M];
getNext(next, p, m);
for(int i = 0, j = -1; i < n; i++){
	// 每次基于已有最长公共前后缀匹配,处理不相同情况
    while(j >= 0 && s[i] != p[j])    j = next[j];
    // 处理相同情况
    if(s[i] == p[j + 1])            j++;
    // 处理匹配成功情况
    if(j == m - 1){		// j初始为-1,少一个数所以对比为n - 1
    	// 输出目标串中所有与模式串匹配的起始位置下标
        printf("%d ", i - m + 1);
        // 为保证最长子序列匹配,因此从后向前进行匹配,将j指向前一个元素的next中的值
     // 还未匹配成功,跳转到待对比位置
        j = next[j];
    }
}

  1. 使用KMP找到含有模式串的起始位置。
    79、【字符串】leetcode ——28. 找出字符串中第一个匹配项的下标(C++版本)

  2. 80、【字符串】leetcode ——459. 重复的子字符串(C++版本)
    方法一:移动匹配,用原始字符串与自身拼接,去掉头部和尾部,当能在新字符串中找到原始字符串时,认为含有可构造成原始字符串的子串元素
    方法二:暴力解法,
    方法三:KMP配合两个结论进行解题:
    (1)字符串长度减去最长相等前后缀长度,得到的剩余部分,为可组成序列的最小重复子串,设长度为n’,n’ = n - next[n - 1]。
    (2)当n可被n’整除时,说明可由该子串构成整个序列,当不能整除时,说明不能由该子串构成整个序列。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

辰阳星宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值