• 【暖*墟】 #字符串# 循环同构串的最小表示法


    循环字符串的最小表示法,即:

    对于一个字符串S,求S的循环的同构字符串S’中字典序最小的一个。

    思路:首先把S复制一份接在它的结尾,得到新串SS。

    那么每个循环串可以表示为SS[ i ~ i+n-1 ](记为b[ i ])

    比较 b[ i ] 和 b[ j ] 。如果 i+k位 > j+k位,则 b[ i ] 一定不是最小同构串。

    还可以得知:b[ i+1 ] ~ b[ i+k ] 也同样不是最小同构串

    因为对于 1<=p<=k ,存在一个比其更小的 b[ j+p ] 。

    所以,b[ i+1 ] ~ b[ i+k ] 可以直接跳过。

    // ↓↓↓ 求出最小同构串的起始位置

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <string>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <stack>
    #include <queue>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    
    //循环同构串的最小表示法(kmp思想)
    
    char s[2000005];
    
    int main(){
        scanf("%s",s+1); 
        int n=strlen(s+1);
        for(int i=1;i<=n;i++) s[n+1]=s[i]; //字符串复制一倍
        int i=1,j=2,k;
        while(i<=n&&j<=n){ 
            for(k=0;k<n&&s[i+k]==s[j+k];k++); //寻找不相等的第一个
            if(k==n) break; //s只由一个字符构成
            if(s[i+k]>s[j+k]){ //i位置开头已经不可能是最小
                i=i+k+1; //跳过i~i+k
                if(i==j) i++; //**特判情况**
            } else{ //j位置开头已经不可能是最小
                j=j+k+1; //跳过j~j+k
                if(i==j) j++;
            }
        } 
        int ans=min(i,j); //最后一次比较中,答案相对大的那一个被+1
        //↑↑↑那么位置较小的就是最小表示的起点位置
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    开发环境之git:团队协作git工作流与常用命令
    js基础梳理-关于this常见指向问题的分析
    Idea 开发环境配置
    Mybatis-generator生成Service和Controller
    分享一个集成在项目中的REST APIs文档框架swagger
    mysql读写分离
    (转)tomcat进程意外退出的问题分析
    shell脚本切割tomcat的日志文件
    (转)Java 详解 JVM 工作原理和流程
    ThreadPoolExecutor-线程池开发的使用
  • 原文地址:https://www.cnblogs.com/FloraLOVERyuuji/p/9337010.html
Copyright © 2020-2023  润新知