蓝桥杯:字符串专题

蓝桥杯备赛题目记录

字符串专题

1、Manacher算法

(1)回文串


※ 回文递归性质

(2)算法内容






(3)例题:最长回文子串

1225.最长回文子串

代码

#include <iostream>
#include <cstring> // 计算字符串str长度时,strlen()会用到
using namespace std;

const int N = 1e6 + 9;
char str[N]; // 字符串
int dp[N]; // 回文半径

int main()
{
    cin >> str + 1; // 从str[1]开始输入
    int n = strlen(str + 1); // 相应地计算str的长度

    for(int i = 2 * n + 1; i >= 1; i --)
    {
        if(i & 1) str[i] = '#'; // 奇数位为字符‘#’
        else str[i] = str[i >> 1]; // 偶数位为原字符
    }
    str[0] = '^', str[2 * n + 2] = '$'; // 二者都是用来占位的,什么符号都无所谓

    int c = 0, r = 0; // c是当前回文子串的中心(关于r),r是当前回文子串的右边界
    for(int i = 1; i <= 2 * n + 1; i ++)
    {
        // 如果当前符号所处位置没有超过回文子串右边界
        if(i < r) dp[i] = min(r - i, dp[2 * c - i]); // 由回文递归性质可得
        else dp[i] = 1; // 否则回文半径为1,因为该回文子串中只含有当前字符

        while(str[i - dp[i]] == str[i + dp[i]]) dp[i] ++; // 以当前字符向两边同步扩展遍历,两边字符相同就是回文
        if(i + dp[i] > r) c = i, r = i + dp[i]; // 如果当前字符所在位置已经超过回文子串右边界,则更新回文子串
    }

    int ans = 0;
    for(int i = 1; i <= 2 * n + 1; i ++) ans = max(ans, dp[i] - 1);
    // (pi + pi -1) / 2 下取整,结果为 pi - 1

    cout << ans << endl;

    return 0;
}

2、KMP算法

(1)定义

(2)算法内容




​ }

(3)例题:斤斤计较的小Z

2047.斤斤计较的小Z

代码

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

void cal_nex(string str2, vector<int>& nex)
{
    nex.resize(str2.length() + 1);
    nex[0] = -1;

    int k = -1, j = 0;

    int len2 = str2.length();
    while(j < len2 - 1)
    {
        if(k == -1 || str2[k] == str2[j])
        {
            k ++, j ++;
            nex[j] = k;
        }
        else k = nex[k];
    }
}

int kmp(string str1, string str2, vector<int>& nex)
{
    int ans = 0;
    cal_nex(str2, nex);

    int k = 0, j = 0;
    int len1 = str1.length(), len2 = str2.length();
    while(j < len1)
    {
        if(k == -1 || str1[j] == str2[k]) k ++, j ++;
        else k = nex[k];

        if(k == len2)
        {
            ans ++;
            k = nex[k];
        }
    }

    return ans;
}

int main()
{
    string str1, str2;
    cin >> str1 >> str2;

    vector<int> nex;
    cout << kmp(str2, str1, nex) << endl;

    return 0;
}

3、字符串哈希

(1)定义



(2)例题:斤斤计较的小Z(同上)

代码

#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1e6 + 5, P = 131;
typedef unsigned long long ULL;

char a[N], b[N];
ULL h1[N], h2[N], p[N];

void my_hash(ULL ha[], int n, char str[])
{
	p[0] = 1;
	for (int i = 1; i <= n; i ++)
	{
		p[i] = p[i - 1] * P;
		ha[i] = ha[i - 1] * P + str[i];
	}
}

ULL get(int l, int r)
{
	return h1[r] - h1[l - 1] * p[r - l + 1];
}

int main()
{
	int aLen, bLen;
	cin >> b + 1 >> a + 1;

	aLen = strlen(a + 1), bLen = strlen(b + 1);
	my_hash(h1, aLen, a);
	my_hash(h2, bLen, b);

	int res = 0;
	for (int i = 1; i + bLen - 1 <= aLen; i ++ )
	{
		int j = i + bLen - 1;
		if (get(i, j) == h2[bLen]) res ++;
	}

	cout << res;
	return 0;
}
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值