AcWing 158. 项链 (最小表示法)

项链

题源:https://www.acwing.com/problem/content/160/

题目

原理:最小表示法

找字典序最小的字符串

循环移位,破环成链 (把原串复制一倍)

memcpy (a + n, a, n);

原理:双指针算法(i j 分别扫过去,挨个比较)

if (s[i + k] > s[j + k])
    i += k + 1;//以剩余那段任何字符开头的 都不是最小表示串,直接跳过
else
    j += k + 1;

特殊情况:i j 开头的串完全相等,说明 s 是循环串,直接break掉

还有 i j 走到相同的地方

(表示已经遍历了一个循环节了,再走下去结果也不会变)

板子:

int find (char* s){
    int i = 0, j = 1;
    while (i < n && j < n){
        int k = 0;
        while (k < n && s[i + k] == s[j + k])
            k ++;
        if (k == n)
            break;
        if (s[i + k] > s[j + k])
            i += k + 1;
        else
            j += k + 1;
        
        if (i == j)
            j ++;//不能走到相同的地方
    }
    int k = min (i, j);
    s[k + n] = 0; //别忘了!!
    return k;
} 

两串不相同

if (strcmp (a + x, b + y))
        cout << "No" << endl;

我滴代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;
const int N = 2e6 + 5;
char a[N], b[N];
int n;

int find (char* s){

    int i = 0, j = 1;
    while (i < n && j < n){
        int k = 0;
        while (k < n && s[i + k] == s[j + k])
            k ++;
        if (k == n)
            break;
        if (s[i + k] > s[j + k])
            i += k + 1;
        else
            j += k + 1;

        if (i == j)
            j ++;//不能走到相同的地方
    }
    int k = min (i, j);
    s[k + n] = 0;
    return k;
} 

int main (){
    cin >> a >> b;
    n = strlen (a);
    memcpy (a + n, a, n);
    memcpy (b + n, b, n);

    int x = find (a), y = find (b);
    if (strcmp (a + x, b + y))
        cout << "No" << endl;
    else
        cout << "Yes" << endl << a + x << endl;

}
posted @ 2022-03-22 16:27  Sakana~  阅读(19)  评论(0编辑  收藏  举报