2019牛客暑期多校训练营(第七场)A-String 【字符串最小表示法+暴力枚举】

2019牛客暑期多校训练营(第七场)A-String 【字符串最小表示法+暴力枚举】

题目:https://ac.nowcoder.com/acm/contest/887/A

大致题意:

给你一个01字符串,要求你用最少的割法,将该字符串分割成数个部分,每个部分都要求是一个对于其自身循环字典序最小的字符串。

参考资料:https://www.cnblogs.com/XGHeaven/p/4009210.html

字符串的最小表示法

思路:

因为数据非常小,字符串长度不超过200,所以即使是O(n^3)也不会TLE,所以不断从原字符串中暴力枚举起点,构造出一个子串,判断其是否是最小表示法,是则输出,否则枚举下一个起点。

代码:

#include<bits/stdc++.h>
using namespace std;

//返回值:该字符串最小表示时应当作为起点的字符的下标
int getmin(char *s, int n) {
    int i=0,j=1,k=0,t;
    while(i<n && j<n && k<n) {
        t=s[(i+k)%n]-s[(j+k)%n];
        if(!t)
			k++;
        else {
            if (t>0) i+=k+1; 
            else j+=k+1;
            if (i==j) j++;
            k=0;
        }
    }
    return i<j?i:j;
}

int main() {
	int cas;
	while(~scanf("%d",&cas)) {
		getchar();
		while(cas--) {
			char ss[1000], temp[1000], count = 0;
			scanf("%s",ss);
			getchar();
			int lenss = strlen(ss);
			for(int i = 0; i < lenss; i++) {
				int j;
				for(j = lenss-1; j >= i; j--) {
					for(int k = i; k <= j; k++) {
						temp[count++] = ss[k];
					}
					temp[count] = '\0';
//					printf("//%s//\n",temp);
					int ret = getmin(temp, count);
					//如果子串的开头就是返回值的话
					//说明该子串就是符合条件的子串
					if(ret == 0) {
						//构造子串
						for(int k = 0; k < count; k++)
							printf("%c",temp[k]);
						//这个i=j很关键
						//让i指针直接跳到下一部分的起点位置
						i = j;
						if(i + 1 < lenss)
							printf(" ");
						count = 0;
						break;
					}
					count = 0;
				}
			}
			printf("\n");
		}
	}
	return 0;
} 

后话:

其实这道题有很多花式解法,这个比较好理解,而且较为通用,至少学到了“字符串的最小/最大表示法”这个新知识。但其实还有O(n)时间复杂度的解法,可以参考这位大佬的博客:
https://blog.csdn.net/weixin_43911945/article/details/98942043

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值