【最小表示法基础 && Code】

本文介绍了一种寻找字符串最小表示法的方法,并通过比较两个字符串的最小表示法来判断它们是否同构。提供了三种不同实现方式的代码示例,包括C风格字符串处理、内存拷贝优化以及使用标准模板库string的高效实现。

Code From http://blog.youkuaiyun.com/cclsoft/article/details/5467743

int MinimumRepresentation(char *s, int l)  
{  
    int i = 0, j = 1, k = 0, t;  
    while(i < l && j < l && k < l) {  
        t = s[(i + k) >= l ? i + k - l : i + k] - s[(j + k) >= l ? j + k - l : j + k];  
        if(!t) k++;  
        else{  
            if(t > 0) i = i + k + 1;  
            else j = j + k + 1;  
            if(i == j) ++ j;  
            k = 0;  
        }  
    }  
    return (i < j ? i : j);  
}

这比ZY的PPT容易懂多了....不过那个博客的博主好像写错了,【否则j++】那里没有改过来。

另外为什么要返回i、j的最小值呢?

注意到i、j后跳的过程中是可能超出l的范围的。


那么,最小表示法的基础练习题:给出两个序列问是否同构。

code:

#include<iostream>
#include<cstdio> 
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})
#define maxlen 8005

using namespace std;

typedef char st[maxlen];

st a, b;
int len;

void init()
{
	freopen("necklace.in", "r", stdin);
	freopen("necklace.out", "w", stdout);
	scanf("%s\n", a);
	scanf("%s\n", b);
	len = strlen(a);
}

int getmin(st c)
{	
	int i = 0, j = 1, k = 0, tmp;
	while (i < len && j < len && k < len)
	{
		tmp = c[i + k >= len ? i + k - len : i + k] - c[j + k >= len ? j + k - len : j + k];
		if (!tmp) ++k;
		else
		{
			if (tmp > 0)
				i += k + 1;
			else
				j += k + 1;
			if (i == j) ++j;
			k = 0;
		}
	}
	return min(i, j);
}

int main()
{
	init();
	int pa = getmin(a), pb = getmin(b);
	for (int i = 0; i < len; ++i)
		if (a[i + pa >= len ? i + pa - len : i + pa] != b[i + pb >= len ? i + pb - len : i + pb])
			{printf("No"); return 0;}
	printf("Yes\n");
	for (int i = 0; i < len; ++i) printf("%c", a[i + pa >= len ? i + pa - len : i + pa]);
	return 0;
}

事实上这样效率还可以提高。

我们不每次判断,改为复制一段到后面。

虽然有点麻烦,但实际上还没有判断的麻烦,而且快了N倍,1.36s的大数据变成0.31s

code

#include<iostream>
#include<cstdio> 
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})
#define maxlen 10000005

using namespace std;

typedef char st[maxlen];

st a, b, d;
int len;

void init()
{
	freopen("necklace.in", "r", stdin);
	freopen("necklace.out", "w", stdout);
	gets(a);
	len = strlen(a);
	strcpy(d, a);
	strcat(a, d);
	gets(b);
	strcpy(d, b);
	strcat(b, d);
}

void getmin(st &c)
{	
	int i = 0, j = 1;
	while (j < len)
	{
		int w = 0;
		while (c[i + w] == c[j + w] && w < len) ++w;
		if (w == len) break;
		if (c[i + w] < c[j + w])
			j += w + 1;
		else
		{
			i += w + 1;
			if (i < j) i = j;
			j = i + 1;
		}
	}
	memset(d, 0, sizeof d);
	memcpy(d, c + i, sizeof(char)* len);
	d[len] = 0;
	memcpy(c, d, sizeof(d));	
}

int main()
{
	init();
	getmin(a), getmin(b);
	if (!strcmp(a, b))
		printf("Yes\n%s", a);
	else
		printf("No");
	return 0;
}

话说忘记strcmp是相同返回0了,弄反,调试半天..


string版

#include<iostream>
#include<cstdio> 
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<climits>
#define ot "%d"
#define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})

using namespace std;

string a, b;
int len;

void init()
{
	freopen("necklace.in", "r", stdin);
	freopen("necklace.out", "w", stdout);
	cin >> a >> b;
	len = a.length();
}

void getmin(string &x)
{
	x = x + x;
	int i = 0, j = 1;
	while (j <= len)
	{
		int k = 0;
		while (k < len && x[i + k] == x[j + k]) ++k;
		if (k == len) break;
		if (x[i + k] < x[j + k])
			j += k + 1;
		else
		{
			if (i + k + 1 <= j)
				i = j;
			else
				i += k + 1;
			j = i + 1;
		}
	}
	x = x.substr(i, len);
}

int main()
{
   ios::sync_with_stdio(false);
	init();
	getmin(a), getmin(b);
	if (a == b)
		cout << "Yes" << endl << a << endl;
	else
		cout << "No";
	return 0;
}

本来慢的要死,后来发现是cin cout的问题,果断ios::sync_with_stdio(false); 然后0.5s左右。

不过string更好写就是。



评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值