竞赛模版

GCD & LCM

int gcd(int a,int b)
{
 	return b ? gcd(b, a % b) : a;
}
int lcm(int a, intb)
{
    return abs(a * b) / gcd(a, b);
}
int a, b, x, y;
int exgcd(int a, int b, int &x, int &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int ans = exgcd(b, a % b, y, x);
    y -= x * (a / b);
    return ans;
}

字符串 <=> 整型

sscanf(s, "%d", &n);//从字符串s中读数n
sprintf(s, "%d", n);//将n转换为字符串s

同余

(a + b) % m = (a % m) + (b % m);
(a - b) % m = (a % m) - (b % m); // 稍微留意负数情况
(a * b) % m = (a % m) * (b % m);
m ^ n % c = (m % c) ^ n % c;

strtok和sscanf结合输入

int main()
{
	char s[] = "ab-cd:ef;gh: i-jkl;mnop;qrs-tu:vwx-y;z";
	char *delim = "-: ";   //分割条件字符串,目前里面有三个字符‘-’,’:’,‘  ’
	char *p;            //当目标字符串s中遇到分割条件字符时自动改写成‘\0’
	printf("%s ", strtok(s, delim));
	while ((p = strtok(NULL, delim)))
		printf("%s ", p);
	printf("\n");
}
int main()
{
	int a, b, c;
	char str[] = "2018:7:15";
	sscanf(str, "%d:%d:%d", &a, &b, &c);
	cout << a << " " << b << " " << c << endl;
}

数组去重

// Eg:1 2 2 3 4 => 1 2 3 4 2
int b[N];
sort(b, b + N);
int len = unique(b, b + n) - b;//返回的是4的位置

n ! n! n! 的位数 – 斯特林公式

这里求到的数和原本的实际值相差不大,故求位数不影响

len = 0.5 * log10(2 * 3.1415927 * n) + n * log10(n / 2.718281828459);
ans = (int)len + 1;

Log与自然对数e

Log(x)表示ln(x) ,其他例如:log10(x) ,log2(x),用exp(x)来表示e^x

分数

储存分数的结构体

struct F
{
    int son, mother; // 分子,分母
    F(int s, int m) : son(s), mother(m) {}
};

化为最简分数

void simplify(F &f)
{
    if (f.son == 0)
    { // 分子为0,分母均变为1
        f.mother = 1;
        return;
    }
    if (f.mother < 0)
    { // 把分母上的负号移到分子上
        f.son = -f.son;
        f.mother = -f.mother;
    }
    int d = gcd(abs(f.son), f.mother); // 求分子分母最大公约数
    f.son /= d;
    f.mother /= d;
}

输出

void output(Fraction &f)
{
    if (f.mother == 1)
        printf("%d", f.son);
    else
    {
        if (abs(f.son) < f.mother)
            printf("%d/%d", f.son, f.mother);
        else
            printf("%d %d/%d", f.son / f.mother, abs(f.son) % f.mother, f.mother);
    }
}

求1到n的数的异或和 O(1)

unsigned xor_n(unsigned n)
{
    unsigned t = n & 3;
    if (t & 1)
        return t / 2u ^ 1; // 照着打就行,u默认为unsigned int
    return t / 2u ^ n;
}

基姆拉尔森公式

卡特兰数

给定一个凸n边形,问将其划分成三角形的方法数
1,1,2,5,14,42,132….

h(n) = h(n - 1) * (4 * n - 2) / (n + 1) h(n) = C(2n, n) / (n + 1);                              
h(0) = 1;

错排公式

Eg:给定n种颜色篮子和n种颜色球,求全放错情况数

D(1) = 0;
D(2) = 1;
D(n) = (n - 1) * (D(n - 2) + D(n - 1));

进制转换

简单输出查看

#include <bitset>
#include <iostream>
using namespace std;
int main()
{
    cout << "35的2进制: " << bitset<8>(35) << endl; //<8>:表示保留8位输出
    cout << "35的8进制:" << oct << 35 << endl;
    cout << "35的10进制" << dec << 35 << endl;
    cout << "35的16进制:" << hex << 35 << endl;
}

其他->十进制

手写

int Atoi(string s, int radix) // s是给定的radix进制字符串
{
    int ans = 0;
    for (int i = 0; i < s.size(); i++)
    {
        char t = s[i];
        if (t >= '0' && t <= '9')
            ans = ans * radix + t - '0';
        else
            ans = ans * radix + t - 'a' + 10;
    }
    return ans;
}

strtol

long int strtol(const char *nptr, char **endptr, int base)
将字符串变为long
base是要转化的数的进制,非法字符会赋值给endptr,nptr是要转化的字符

#include<cstdio>
int main()  
{  
    char buffer[20]="10549stend#12";  
    char *stop;  
    int ans=strtol(buffer, &stop, 8);   //将八进制数1054转成十进制,后面均为非法字符
    printf("%d\n",ans);  
    printf("%s\n", stop);   
}

十进制->其他

手写

string intToA(int n, int radix) // n是待转数字,radix是指定的进制
{
    string ans = "";
    do
    {
        int t = n % radix;
        if (t >= 0 && t <= 9)
            ans += t + '0';
        else
            ans += t - 10 + 'a';
        n /= radix;
    } while (n != 0); // 使用do{}while()以防止输入为0的情况
    reverse(ans.begin(), ans.end());
    return ans;
}

itoa() Win特有

char *itoa(int value, char *string, int radix);

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

int main()
{
    int num = 100;
    char s[25];
    itoa(num, s, 100);
    cout << s; // 输出100
}

sprintf() 通用

char s[255];
sprintf(s, "%x", 100); //将100转为16进制表示的字符串。
#include<cstdio>  
int main()  
{  
	char s[100]={0};
	sprintf(s, "%d", 123); //十进制输出产生"123"
	sprintf(s, "%4d%4d", 123, 4567); //指定宽度不足的左边补空格,产生:" 1234567"
	sprintf(s, "%8o", 123);	//八进制输出,宽度占8个位置
	sprintf(s, "%8x", 4567); //小写16 进制,宽度占8个位置,右对齐
	sprintf(s, "%10.3f", 3.1415626); //产生:" 3.142"
	int i = 100;
	sprintf(s, "%.2f", i);	//注意这是不对的
	sprintf(s, "%.2f", (double)i);	//要按照这种方式才行
}  

全排列

数字

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

int main()
{
    int a[4] = {1, 2, 3, 4};
    sort(a, a + 4);
    do
    {
        for (int i = 0; i < 4; i++)
            cout << a[i] << " ";
        cout << endl;
    } while (next_permutation(a, a + 4));
    return 0;
}

字母

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    string s;
    cin >> s;
    sort(s.begin(), s.end());
    do
    {
        cout << s << endl;
    } while (next_permutation(s.begin(), s.end()));
}

第n个排列

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

int main()
{
    int a[7] = {1, 2, 3, 4, 5, 6, 7};
    sort(a, a + 7);
    int n = 0;
    do
    {
        if (n == 1654)
        {
            for (int i = 0; i < 7; i++)
                cout << a[i];
            cout << endl;
            break;
        }
        n++;
    } while (next_permutation(a, a + 7));
}

素数

判定

bool check(long long n)
{
    if (n <= 3)
        return n > 1;
    if (n % 6 != 1 && n % 6 != 5)
        return false;
    int t = sqrt(n);
    for (long long i = 5; i <= t; i += 6)
    {
        if (n % i == 0 || n % (i + 2) == 0)
            return false;
    }
    return true;
}

生成n个素数

int ans[100005];
bool vis[10000000];

void CreatPrime()
{
    int cnt = 1;
    for (int i = 2; i < 1300000; i++)
    {
        if (vis[i])
            continue;
        for (int j = i + i; j < 10000000; j += i)
            vis[j] = true;
        if (!vis[i])
            ans[cnt++] = i;
        if (cnt > 100000)
        {
            break;
        }
    }
    int PrimeNum;
    cin >> PrimeNum;
    {
        for (int i = 1; i <= PrimeNum; i++)
            printf("%d ", ans[i]);
    }
}

生成n以为的素数表

vector<int> prime; // 素数表存储在prime中,prime是全局变量
void findPrime(int n)
{
    vector<bool> f(n, false);
    for (int i = 2; i < n; ++i)
        if (!f[i])
        {
            prime.push_back(i);
            for (int j = i + i; j < n; j += i)
                f[j] = true;
        }
}

将n质因子分解

map<int, int> factor; // 质因子在factor中,键表示质因子,值表示该质因子个数,注意map会按键排序
void getFactor(int n)
{
    if (n == 1)
    {
        factor[1] = 1;
        return;
    }
    findPrime(n + 1); // 打印n+1以内的素数表存储到prime中
    for (int i : prime)
    {
        while (n % i == 0)
        {
            ++factor[i];
            n /= i;
        }
        if (n == 1)
            break;
    }
}

日期处理

// 给定年月日O(1)算周数
int CaculateWeekDay(int y, int m, int d)
{
    if (m == 1 || m == 2)
    {
        m += 12;
        y--;
    }
    int iWeek = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
    return iWeek;
} 
// 周日用数字0表示
// 判断y年m月有几天
int monthdays[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 平年时每个月有多少天
int daysOfMonth(int y, int m)
{                                                              
    if ((y % 400 == 0 || y % 4 == 0 && y % 100 != 0) && m == 2) // y年是闰年且查询2月有几天
        return 29;                                              // 闰年2月有29天
    return monthdays[m];                                        // 直接返回monthdays的相应位置的天数
}

// 根据1850年1月1日是周二,返回y年m月d日是周几
int determineWeek(int y, int m, int d, int week = 2)
{
    for (int i = 1850; i < y; ++i)
    {                                                                        // 检查1850年到y年经历的年份
        int temp = (i % 400 == 0 || i % 4 == 0 && i % 100 != 0) ? 366 : 365; // 平年有365天,闰年有366天
        week = (week + temp) % 7;                                            // 更新week
    }
    for (int i = 1; i < m; ++i)                // 检查1月到m月的月份
        week = (week + daysOfMonth(y, i)) % 7; // 求出该月有几天,并更新week
    return (week + d - 1) % 7;                 // 返回周几,注意周日用0表示
}

// 判断y年m月第b个星期c是几号
int determineDayOfNumberWeek(int y, int m, int b, int c)
{                                     
    int week = determineWeek(y, m, 1); // 确定y年m月1日是周几
    return 1 + (c + 7 - week) % 7 + 7 * (b - 1);
}

快速幂

typedef long long LL
LL pow_mod(LL a, LL n)
{
    LL res = 1;
    while (n)
    {
        if (n & 1)
            res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}

龟速乘

速度较慢,但不会爆long long

long long quick_mul(long long x, long long y, long long mod)
{
    long long ans = 0;
    while (y != 0)
    {
        if (y & 1 == 1)
            ans += x, ans %= mod;
        x = x + x, x %= mod;
        y >>= 1;
    }
    return ans;
}

long long quick_pow(long long x, long long y, long long mod)
{
    long long sum = 1;
    while (y != 0)
    {
        if (y & 1 == 1)
            sum = quick_mul(sum, x, mod), sum %= mod;
        x = quick_mul(x, x, mod), x %= mod;
        y = y >> 1;
    }
    return sum;
}

快速幂里的x是指数级增长,而龟速乘变成了翻倍,仅此而已。

快速乘

本来存进long long会炸掉的值先进行计算,用long double暂时存下,然后再把差值——一个不会超过long long的数字塞回去,再特判一下精度问题

cin >> a >> b >> mod;
cout << ((a * b - (long long)((long double)a * b / mod) * mod + mod) % mod);

矩阵快速幂

int f = 2;
long long n, mod = 1024;
struct node
{
    LL materix[3][3];
};
node mul(node a, node b)
{
    node res;
    memset(res.materix, 0, sizeof(res.materix));
    for (int i = 1; i <= f; ++i)
    {
        for (int j = 1; j <= f; ++j)
        {
            for (int k = 1; k <= f; ++k)
            {
                res.materix[i][j] = (res.materix[i][j] + a.materix[i][k] * b.materix[k][j]) % mod;
            }
        }
    }
    return res;
}
node ksm(node a, long long b)
{
    node ans;
    memset(ans.materix, 0, sizeof(ans.materix));
    for (int i = 1; i <= f; ++i)
        ans.materix[i][i] = 1;
    while (b)
    {
        if (b & 1LL)
            ans = mul(ans, a);
        a = mul(a, a);
        b >>= 1LL;
    }
    return ans;
}

重载版

struct node
{
    LL materix[7][7];
    void init()
    {
        memset(materix, 0, sizeof(materix));
    }
    void init1()
    {
        memset(materix, 0, sizeof(materix));
        for (int i = 1; i <= ff; ++i)
            materix[i][i] = 1;
    }
    node operator*(const node B) const
    {
        node C;
        C.init();
        for (int i = 1; i <= ff; ++i)
        {
            for (int j = 1; j <= ff; ++j)
            {
                for (int k = 1; k <= ff; ++k)
                {
                    C.materix[i][j] = (materix[i][k] * B.materix[k][j] + C.materix[i][j]) % mod;
                }
            }
        }
        return C;
    }
    node ksm(node a, long long b)
    {
        node ans;
        ans.init1();
        while (b)
        {
            if (b & 1LL)
                ans = ans * a;
            a = a * a;
            b >>= 1;
        }
        return ans;
    }
}

KMP算法

在一个文本串 S 内查找一个模式串 P 的出现位置

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 7;
int s[MAXN], p[MAXN];
int slen, plen;
int nex[MAXN];

void GetNext()
{
    int i, j;
    i = 0;
    j = nex[0] = -1;
    while (i < plen)
    {
        while (-1 != j && p[i] != p[j])
            j = nex[j];
        if (p[++i] == p[++j])
            nex[i] = nex[j];
        else
            nex[i] = j;
    }
}

int KMP()
{
    GetNext();
    int i, j;
    i = j = 0;
    while (i < slen && j < plen)
    {
        while (-1 != j && s[i] != p[j])
            j = nex[j];
        i++;
        j++;
    }
    if (j == plen)
        return i - j + 1;
    else
        return -1;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d %d", &slen, &plen);
        for (i = 0; i < slen; i++)
            cin >> s[i];
        for (i = 0; i < plen; i++)
           cin >> p[i];
        cout << KMP() << endl;
    }
    return 0;
}
void getNext(string pattern, int *next)
{
    int j = -1;
    next[0] = -1;
    for (int i = 1; i < pattern.size(); ++i)
    {
        while (j != -1 && pattern[i] != pattern[j + 1])
            j = next[j];
        if (pattern[i] == pattern[j + 1])
            ++j;
        next[i] = j;
    }
}
bool KMP(string text, string pattern)
{
    int next[pattern.size()];
    getNextval(pattern, next);
    for (int i : next)
        printf("%d ", i);
    int j = -1;
    for (int i = 0; i < text.size(); ++i)
    {
        while (j != -1 && text[i] != pattern[j + 1])
            j = next[j];
        if (text[i] == pattern[j + 1])
            ++j;
        if (j == pattern.size() - 1)
            return true;
    }
    return false;
}
void getNextval(string pattern, int *next)
{
    int j = -1;
    next[0] = -1;
    for (int i = 1; i < pattern.size(); ++i)
    {
        if (j != -1 && pattern[i] != pattern[j + 1])
            j = next[j];
        if (pattern[i] == pattern[j + 1])
            ++j;
        if (j == -1 || pattern[i + 1] != pattern[j + 1])
            next[i] = j;
        else
            next[i] = next[j];
    }
}
int KMPcount(string text, string pattern)
{
    int next[pattern.size()];
    getNextval(pattern, next);
    for (int i : next)
        printf("%d ", i);
    int j = -1, result = 0;
    for (int i = 0; i < text.size(); ++i)
    {
        while (j != -1 && text[i] != pattern[j + 1])
            j = next[j];
        if (text[i] == pattern[j + 1])
            ++j;
        if (j == pattern.size() - 1)
        {
            ++result;
            j = next[j];
        }
    }
    return result;
}

并查集

int father[MAX];

// 初始化并查集
void init(int n)
{
    iota(father, father + n, 0);
}

// 寻找根结点并进行路径压缩
int findFather(int x)
{ 
    if (x == father[x])
        return x;
    int temp = findFather(father[x]);
    father[x] = temp;
    return temp;
}

// 合并两个集合
void unionSet(int a, int b)
{
    int ua = findFather(a), ub = findFather(b);
    if (ua != ub)
        father[ua] = ub;
}

// 求出并查集中有几个集合
int countRoot(int n)
{ 
    int num = 0;
    for (int i = 0; i < n; ++i)
        if (father[i] == i)
            ++num;
    return num;
}

最近公共祖先(LCA)问题

倍增法

struct Node
{                            // 结点类
    int data, father, level; // 权值、父节点在pre中的下标、深度
    Node(int d = 0, int f = -1, int l = 0) : data(d), father(f), level(l) {}
};
Node tree[MAX];

// 倍增法解LCA问题,返回最近公共祖先在tree中的下标
int LCA(int a, int b)
{ 
    int ia = -1, ib = -1;

    // 找到两个结点在pre数组中的下标
    for (int i = 0; i < n; ++i)
    { 
        if (tree[i].data == a)
            ia = i;
        if (tree[i].data == b)
            ib = i;
    }
    if (ia == -1 || ib == -1) // 结点不在树中,返回-1
        return -1;
        
    // 让ia指向深度更大的结点
    if (pre[ia].level < pre[ib].level) 
        swap(ia, ib);

    // 将二者调整到同一深度
    while (pre[ia].level > pre[ib].level) 
        ia = pre[ia].father;

    // ia,ib同时向上调整,直至二者指向同一结点
    while (ia != ib)
    { 
        ia = pre[ia].father;
        ib = pre[ib].father;
    }
    return ia;
}

逆元

费马小定理

long long quickpow(long long a, long long b)
{
    if (b < 0)
        return 0;
    long long res = 1;
    a %= mod;
    while (b)
    {
        if (b & 1)
            res = (res * a) % mod;
        a = (a * a) % mod;
        b >= 1;
    }
    return res;
}
long long inv(long long a)
{
    return quickpow(a, mod - 2);
}

扩展欧几里得

long long exgcd(long long a, long long b, long long &x, long long &y)
{
    if (!b)
    {
        x = 1;
        y = 0;
        return a;
    }
    else
    {

        long long r = exgcd(b, a % b, y, x);
        y -= x * (a / b);
        return r;
    }
}
long long inv(long long a)
{
    long long x, y;
    long long d = exgcd(a, mod, x, y);
    return x = (x + mod) % mod;
}

打表

long long inv[N];
void prepare_inv(int n, int M)
{
    inv[1] = 1;
    for (int i = 2; i <= n; ++i)
    {
        inv[i] = (long long)(M - M / i) * inv[M % i] % M;
    }
}

大数

输入输出

void scan(__int128 &x)
{
    int f = 1;
    char ch;
    x = 0;
    if (ch = getchar() == '-')
        f = -1;
    else
        x += ch - '0';
    while ((ch == getchar()) >= '0' && ch <= '9')
        x = x * 10 + ch - '0';
    x *= f;
}
void print(__int128 x)
{
    if (!x)
        return;
    if (x < 0)
        putchar('-'), x = -x;
    print(x / 10);
    putchar(x % 10 + '0');
}
__int128 vi(__int128 a, __int128 b)
{
    __int128 mod = b + 2;
    __int128 res = 1;
    while (b)
    {
        if (b & 1)
            res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

高精度加法

struct node
{
    int c[N], l;
    node() { l = 0; }
    void print()
    {
        for (int i = l; i >= 1; i--)
            printf("%d", c[i]);
        printf("\n");
    }
} a, b, ans;
node operator+(const node &a, const node &b)
{
    node res;
    int i;
    res.l = max(a.l, b.l);
    for (i = 1; i <= res.l; i++)
        res.c[i] = a.c[i] + b.c[i];
    for (i = 1; i < res.l; i++)
        res.c[i + 1] += res.c[i] / 10, res.c[i] %= 10;
    while (res.c[res.l] > 9)
        res.c[res.l + 1] = res.c[res.l] / 10, res.c[res.l] %= 10, res.l++;
    while (res.c[res.l] == 0 && res.l > 1)
        res.l--;
    return res;
}

高精度减法

struct node
{
    int c[N], l;
    node() { l = 0; }
    void print()
    {
        for (int i = l; i >= 1; i--)
            printf("%d", c[i]);
        printf("\n");
    }
} a, b, ans;
node operator-(const node &a, const node &b)
{
    node res;
    res.l = max(a.l, b.l);
    for (int i = 1; i <= res.l; i++)
        res.c[i] = a.c[i] - b.c[i];
    for (int i = 1; i < res.l; i++)
        if (res.c[i] < 0)
            res.c[i] += 10, res.c[i + 1]--;
    while (res.c[res.l] == 0 && res.l > 1)
        res.l--;
    return res;
}
bool operator>(const node &a, const node &b)
{
    if (a.l != b.l)
        return a.l > b.l;
    for (int i = a.l; i >= 1; i--)
        if (a.c[i] != b.c[i])
            return a.c[i] > b.c[i];
    return 0;
}

高精度乘法

struct node
{
    int c[N], l;
    node() { l = 0; }
    void print()
    {
        for (int i = l; i >= 1; i--)
            printf("%d", c[i]);
        printf("\n");
    }
} a, b, ans;
node operator*(const node &a, const node &b)
{
    node res;
    res.l = a.l + b.l - 1;
    for (int i = 1; i <= a.l; i++)
        for (int j = 1; j <= b.l; j++)
            res.c[i + j - 1] += a.c[i] * b.c[j];
    for (int i = 1; i < res.l; i++)
        res.c[i + 1] += res.c[i] / 10, res.c[i] %= 10;
    while (res.c[res.l] > 9)
        res.c[res.l + 1] += res.c[res.l] / 10, res.c[res.l] %= 10, res.l++;
    while (res.c[res.l] == 0 && res.l > 1)
        res.l--;
    return res;
}

背包

// 01
int dp[MAXN];
for (int i = 0; i < n; i++)
    for (int j = W; j >= w[i]; j--)
        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
printf("%d\n", dp[W]);

// 完全
int dp[MAXN];
for (int i = 0; i < n; i++)
    for (int j = w[i]; j <= W; j++)
        dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
printf("%d\n", dp[W]);

// 多重背包
for (int i = 0; i < n; i++)
{
    int num = m[i]; // 用来找a
    for (int k = 1; num > 0; k < <= 1)
    {
        int mul = min(k, num);
        for (int j = W; j >= w[i] * mul; j--)
        {
            dp[j] = max(dp[j], dp[j - w[i] * mul] + v[i] * mul);
        }
        num -= mul;
    }
}
printf("%d\n", dp[W]);

并查集

// 并查集(路径压缩)
const int max_n = 100005;
int par[max_n];

void init(int n)
{ // 初始化
    for (int i = 1; i <= n; i++)
        par[i] = i;
}

int find(int x)
{ // 查找x所在集合的根
    if (par[x] != x)
        par[x] = find(par[x]); // 递归返回的同时压缩路径
    return par[x];
}

void unite(int x, int y)
{ // 合并x与y所在集合
    x = find(x);
    y = find(y);
    par[x] = y;
}

bool same(int x, int y)
{ // x与y在同一集合则返回真
    return find(x) == find(y);
}

求二进制下1的个数

int bitcount(unsigned int n)
{
    int count = 0;
    while (n)
    {
        count++;
        n &= (n - 1);
    }
    return count;
}

马拉车

public String preProcess(String s) {
    int n = s.length();
    if (n == 0) {
        return "^$";
    }
    String ret = "^";
    for (int i = 0; i < n; i++)
        ret += "#" + s.charAt(i);
    ret += "#$";
    return ret;
}

// 马拉车算法
public String longestPalindrome2(String s) {
    String T = preProcess(s);
    int n = T.length();
    int[] P = new int[n];
    int C = 0, R = 0;
    for (int i = 1; i < n - 1; i++) {
        int i_mirror = 2 * C - i;
        if (R > i) {
            P[i] = Math.min(R - i, P[i_mirror]);// 防止超出 R
        } else {
            P[i] = 0;// 等于 R 的情况
        }

        // 碰到之前讲的三种情况时候,需要利用中心扩展法
        while (T.charAt(i + 1 + P[i]) == T.charAt(i - 1 - P[i])) {
            P[i]++;
        }

        // 判断是否需要更新 R
        if (i + P[i] > R) {
            C = i;
            R = i + P[i];
        }

    }

    // 找出 P 的最大值
    int maxLen = 0;
    int centerIndex = 0;
    for (int i = 1; i < n - 1; i++) {
        if (P[i] > maxLen) {
            maxLen = P[i];
            centerIndex = i;
        }
    }
    int start = (centerIndex - maxLen) / 2; //最开始讲的求原字符串下标
    return s.substring(start, start + maxLen);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值