字符串最大最小表示法

什麼是循環字符串的最小表示法

就是對於一個字符串來講,其同構字符串中字典序最小的一個ios

好比說:S = bacd,則其同構字符串有 acdb、cdba、dbac,其中acdb事S串的最小表示法,由於其字典序最小c++

如何求字符串的循環同構的最小表示

暴力的方法是,你將全部的同構都寫出來,如何拍個序,輸出第一個就能夠,可是這樣複雜度很高,沒得作函數

因此咱們能夠這樣作:優化

用兩個指針來求,i指向最小表示的位置,j爲比較指針,最終輸出i,即位最小的開頭位置
令i = 0,j = 1.
  若是S[i] > S[j]	說明當前i指向的位置必定不是最小表示的起點位置,j比i小,因此j相比i來講能夠是最小的起點,因此修改i的值爲j,再讓j++
  若是說S[i] < S[j]說明當前j指向的位置必定不是最小表示的起點位置,因此讓j++
  若是說S[i] = S[j],就須要在此基礎上進行接下來的比較,此時須要保持i和j的位置不變,比較後面的元素,因此須要一個新的變量k來代替ij移動,達到比較的目的
  比較S[i + k]與S[j + k],若是S[i + k] = S[j + k],則讓k++,繼續比下去
  若是S[i + k] < S[j + k],則k++,須要繼續比下去
  若是S[i + k] > S[j + k],說明i位置開頭的字符串並非最小表示,j位置開頭的字符串是比他小的,因此讓i = j,j++
  記得每次比較完S[i + k]與S[j + k]不一樣時要將k賦值爲0
 最後返回i的位置便可

這樣的方法也不是最優解,面對aaaaaaaaaab這類的毒瘤數據,就會被卡的死死的,由於i的指針每次只會移動1個方位,時間複雜度也很高spa

因此,還須要進行優化:.net

對於S[i + k] < S[j + k]時,說明j不是最小表示,那麼咱們就能夠移動j = j + k + 1;一樣的,對於S[i + k] > S[j + k]時,說明i不是最小表示,就讓i = i + k + 1。最後返回i與j中最小的值便可(其實返回i就好了,能過,可是保險起見仍是返回最小值叭指針

爲何呢?code

拿S[i + k] < S[j + k]來講叭,其 j 到 k 中間位置的任意位置爲起點都會大於以i爲起點的,由於從i開頭和從j開頭走的前k個位置的值是相等的,因此可能的小的位置是在j + k + 1後面的ci

代碼實現

int getmin(string s)
{
    ll m = s.size();
    int i = 0, j = 1, k = 0;
    while (i < m && j < m && k < m) {
        int t = s[(i + k) % m] - s[(j + k) % m];
        if(t == 0)k++;
        else
        {
            if(t > 0)i += k + 1;
            else j += k + 1;
            if(i == j) j++;
            k = 0;
        }
    }
    return min(i, j);
}

例題:

How many字符串

題意:

給你一堆字符串,問你非同構字符串有幾個

思路:

對每一個字符串都進行求最小表示法,將其塞到set中去重

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <queue>
#include <stdlib.h>
#include <sstream>
#include <map>
#include <set>
using  namespace std;
#define MAX 100000 + 5
typedef  long long ll;
map<string,int>mp;
set<string>se;
void getmin(string ss, ll m)
{
    int i = 0, j = 1, k = 0, t;
    while (i < m && j < m && k < m) {
        t = ss[(i + k) % m] - ss[(j + k) % m];
        if(t == 0)
            k++;
        else
        {
            if(t > 0) i += k + 1;
            else j += k + 1;
            if(i == j) j++;
            k = 0;
        }
    }
    int a = min(i, j);//取最小值
    string sss = "";
    for(int p = 0; p < m; p++)//字符串拼接,有個函數來着,可是我也不知道爲何用不了
    {
        sss += ss[(p + a) % m];
    }
    se.insert(sss);
}
int main()
{
    int n;
    string s;
    while (cin>>n) {
        se.clear();//記得清0
        for(int i = 1; i <= n; i++)
        {
            cin>>s;
            ll m = s.size();
            getmin(s, m);
        }
        cout<<se.size()<<endl;
    }
}

最大表示法

int getmin(string s)
{
    ll m = s.size();
    int i = 0, j = 1, k = 0;
    while (i < m && j < m && k < m) {
        int t = s[(i + k) % m] - s[(j + k) % m];
        if(t == 0)k++;
        else
        {
            if(t > 0)j += k + 1;
            else i += k + 1;
            if(i == j) j++;
            k = 0;
        }
    }
    return min(i, j);
}

就將else裏面的那兩個換個位置

相關文章
相關標籤/搜索