就是對於一個字符串來講,其同構字符串中字典序最小的一個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裏面的那兩個換個位置