就是对于一个字符串来说,其同构字符串中字典序最小的一个
比如说:S = bacd,则其同构字符串有 acdb、cdba、dbac,其中acdb事S串的最小表示法,因为其字典序最小
暴力的方法是,你将所有的同构都写出来,如何拍个序,输出第一个就可以,但是这样复杂度很高,没得做
所以我们可以这样做:
用两个指针来求,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个方位,时间复杂度也很高
所以,还需要进行优化:
对于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就行了,能过,但是保险起见还是返回最小值叭
为什么呢?
拿S[i + k] < S[j + k]来说叭,其 j 到 k 中间位置的任意位置为起点都会大于以i为起点的,因为从i开头和从j开头走的前k个位置的值是相等的,所以可能的小的位置是在j + k + 1后面的
?
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);
}
给你一堆字符串,问你非同构字符串有几个
对每个字符串都进行求最小表示法,将其塞到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里面的那两个换个位置
原文:https://www.cnblogs.com/chelsea0901/p/14400929.html