zoukankan      html  css  js  c++  java
  • 最小表示法

    字符串的最小表示法

    http://poj.org/problem?id=1509

    字符串最小表示法:以某个小标开始字典序最小的串。

    假设有两个下标i,j,表示如果从i和从j出发的字符串,有一个k表示字符串的长度,如果长度达到len,就表示找到最小的串。

    s[i+k] == s[j+k]:  k++

    s[i+k]>s[j+k]: i=i+k+1 表示以i,到i+k为起点的字符串,都不是最小字符串的前缀。

    s[i+k]<s[j+k]: j=j+k+1 同理

    注意:1.i和j一定是不同的。

              2.每次不等时,需要设置k为0。

    简单说,就是需要几步才能成为最小字符串
    
    当为1时已经是最小
     1 #include<iostream>
     2 #include<string>
     3 using namespace std;
     4 int findMin(string s)
     5 {
     6     int len = s.length();
     7     int i=0,j=1,k=0;
     8     while(i<len&&k<len&&j<len)
     9     {
    10         if(s[(i+k)%len]==s[(j+k)%len])
    11         {
    12             k++;
    13         }
    14         else if(s[(i+k)%len]>s[(j+k)%len])
    15         {
    16             i=i+k+1;
    17             k=0;
    18         }
    19         else
    20         {
    21             j=j+k+1;
    22             k=0;
    23         }
    24         if(i==j) j++;
    25     }
    26     return min(i,j);
    27 }
    28 int main()
    29 {
    30     int n;
    31     string s;
    32     cin>>n;
    33     while(n--)
    34     {
    35         cin>>s;
    36         cout<<findMin(s)+1<<endl;
    37     }
    38     return 0;
    39 }
    View Code

    上面这个更好理解

    算法用法
    最小表示法是我在看插头DP的时候看到的一个名词,就先来看了一下这个算法,还是蛮简单的,有一个首位相连的字符串,我们要寻找一个位置,从这个位置向后形成一个新字符串,我们需要使这个字符串字典序最小。

    算法解释
    我们这里要i = 0,j = 1,k = 0,表示从i开始k长度和从j开始k长度的字符串相同(i,j表示当前判断的位置)

    当我们str[i] == str[j]时,根据上面k的定义,我们的需要进行k+1操作

    当str[i] > str[j]时,我们发现i位置比j位置上字典序要大,那么不能使用i作为开头了,我们要将i向后移动,移动多少呢?有因为i开头和j开头的有k个相同的字符,那么就执行 i = i + k +1

    相反str[i] < str[j]时,执行:j = j + k +1 

    最终i和j中较小的值就是我们最终开始的位置

    相反如果是最大表示法的话,我们就要求解字典序最大的字符串,那么我们只需要在执行第二或第三个操作时选择较大的那个位置较好了

    模板

     1 int Get_min()
     2 {
     3     int n = strlen(s);
     4     int i = 0,j = 1,k = 0,t;
     5     //表示从i开始k长度和从j开始k长度的字符串相同
     6     while(i < n && j < n && k < n)
     7     {
     8         t = s[(i+k)%n] - s[(j+k)%n];
     9         //t用来计算相对应位置上那个字典序较大
    10         if(!t) k++;//字符相等的情况
    11         else
    12         {
    13             if(t > 0) i += k+1;//i位置大,最大表示法: j += k+1
    14             else j += k+1;//j位置大,最大表示法: i += k+1
    15             if(i == j) j++;
    16             k = 0;
    17         }
    18     }
    19     return i >j ?j :i;
    20 }
    View Code

    栗子

    有一个最小表示的裸题,POJ 1509

    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <cstdio>
     
    using namespace std;
    char s[11000];
    int Get_min()
    {
        int n = strlen(s);
        int i = 0,j = 1,k = 0,t;
        //表示从i开始k长度和从j开始k长度的字符串相同
        while(i < n && j < n && k < n)
        {
            t = s[(i+k)%n] - s[(j+k)%n];
            //t用来计算相对应位置上那个字典序较大
            if(!t) k++;//字符相等的情况
            else
            {
                if(t > 0) i += k+1;//i位置大
                else j += k+1;//j位置大
                if(i == j) j++;
                k = 0;
            }
        }
        return i >j ?j :i;
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i = 0;i < n;i ++)
        {
            scanf("%s",s);
            printf("%d
    ",Get_min()+1);
        }
    }
    View Code
  • 相关阅读:
    mysql 数据库引擎
    dubbo 微服务
    spring 属性文件加载接口---PropertySourceLoader
    Shiro架构
    HTTP状态码
    Shiro 修改权限,刷新权限
    Consul 架构(译)
    Java EE平台介绍(译)
    Java SPI机制
    Otb_000_ElementUI 的 Drawer组件无法上下滚动没有滚动条
  • 原文地址:https://www.cnblogs.com/DWVictor/p/10225041.html
Copyright © 2011-2022 走看看