就是对于一个字符串来讲,其同构字符串中字典序最小的一个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里面的那两个换个位置