zoukankan      html  css  js  c++  java
  • HDU 3374 String Problem (KMP+最大最小表示)

    题意

    输出一个字符串字典序最大最小表示是从哪一位开始,而且输出数量.

    思路

    数量好求,肯定是字符串的循环节,循环节可以直接通过KMP的Next数组得到POJ 2406 最小周期子串)。 对于最大最小表示法,就是将字符串不断旋转,得到字典序最大或者最小的。 求字符串最小表示的方法: (1)  利用两个指针p1, p2。初始化时p1指向s[0], p2指向s[1]。 (2)  k = 0开始,检验s[p1+k] 与 s[p2+k] 对应的字符是否相等,如果相等则k++,一直下去,直到找到第一个不同,(若k试了一个字符串的长度也没找到不同,则那个位置就是最小表示位置,算法终止并返回)。则该过程中,s[p1+k] 与 s[p2+k]的大小关系,有三种情况: (A). s[p1+k] > s[p2+k],则p1滑动到p1+k+1处 --- 即s1[p1->p1+k]不是该循环字符串的“最小表示”的前缀。 k置为0 (B). s[p1+k] < s[p2+k],则p2滑动到p2+k+1处, k置为0 (C). s[p1+k] = s[p2+k],则 k++; if (k == len) 返回结果。 注:这里滑动方式有个小细节,若滑动后p1 == p2,将正在变化的那个指针再+1。直到p1、p2把整个字符串都检验完毕,返回两者中小于 len 的值。 (3)   如果 k == len, 则返回p1与p2中的最小值 最大表示法一样,大小于的时候改变一下就照了,可以写在一个函数里面。  

    代码

      [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; typedef long long LL; const int maxlen = 1000005; struct StringMatching{ char s[maxlen], p[maxlen]; int next[maxlen]; vector <int> match; void get_next(){ int len = strlen(p); next[0] = -1; int j = -1; for(int i = 1; i < len; i ++){ while(j > -1 && p[i] != p[j+1]) j = next[j]; if (p[i] == p[j+1]) j ++; next[i] = j; } } int solve(){ int num = 0, j = -1; get_next(); int len1 = strlen(s), len2 = strlen(p); match.clear(); for (int i = 0; i < len1; i ++){ while(j > -1 && s[i] != p[j+1]) j = next[j]; if (s[i] == p[j+1]) j ++; if (j == len2 - 1){ num ++; //匹配次数 match.push_back(i); //匹配位置 j = next[j]; } } return num; } }kmp; //字符串最大最小表示法,flag = 1表示最小表示法 #define MIN_EXPRESS 1 #define MAX_EXPRESS 0 int min_max_express(char *s, bool flag){ int len = strlen(s); int i = 0, j = 1, k = 0; while(i < len && j < len && k < len){ int t = s[(j+k)%len] - s[(i+k)%len]; if (t == 0) k ++; else{ if (t > 0){ if (flag){ j += k + 1; } else{ i += k + 1; } } else{ if (flag){ i += k + 1; } else{ j += k + 1; } } if (i == j) j ++; k = 0; } } return min(i, j); } int main(){ //freopen("test.in", "r", stdin); //freopen("test.out", "w", stdout); while(scanf("%s", kmp.p) != EOF){ int min_express = min_max_express(kmp.p, MIN_EXPRESS); int max_express = min_max_express(kmp.p, MAX_EXPRESS); kmp.get_next(); int len = strlen(kmp.p); int ans = len - (kmp.next[len-1]+1); if (len % ans != 0) ans = 1; else ans = len / ans; printf("%d %d %d %d ", min_express + 1, ans, max_express + 1, ans); } return 0; } [/cpp]
  • 相关阅读:
    递归函数及Java范例
    笔记本的硬盘坏了
    “References to generic type List should be parameterized”
    配置管理软件(configuration management software)介绍
    WinCE文件目录定制及内存调整
    使用Silverlight for Embedded开发绚丽的界面(3)
    wince国际化语言支持
    Eclipse IDE for Java EE Developers 与Eclipse Classic 区别
    WinCE Heartbeat Message的实现
    使用Silverlight for Embedded开发绚丽的界面(2)
  • 原文地址:https://www.cnblogs.com/AbandonZHANG/p/4114113.html
Copyright © 2011-2022 走看看