现在的位置: 首页 > 综合 > 正文

字符串的故事(AC,代码有点长)

2013年10月10日 ⁄ 综合 ⁄ 共 5139字 ⁄ 字号 评论关闭

字符串的故事

Time Limit:1000MS  Memory Limit:65536K
Total Submit:272 Accepted:48

Description

从前,有一串很长很长的字符串,它由n个小写字母组成。有一天它在照镜子的时候,觉得自己太肥了,于是它想减肥。减肥的时候,可以不断地去掉第一个或者最后一个字符。它希望自己减肥之后,对于小写字母a、b、c,自己身上都至少保留有一个。它想知道自己减肥后的最小长度,你能帮帮它吗?

Input

第一行有一个数字t(t ≤ 20),表示共t组数据。
接下来t行,每行有一串由小写字母组成的字符串,字符串的长度n < 100000。保证字符串中包含有小写字母a、b、c

Output

总共t行,每行输出一个数字,表示该组数据求得的最小长度。

Sample Input

2
ccbaa
abbbbbbbbbc

Sample Output

3
11

Hint

对于sample第一组数据,可以删去头尾两个字符,剩下的cba是符合要求且长度最小的。

Source

yzq

 

解法三:通用解法,可以将字符扩展到26个字符,即是为学论坛每日一题系列--最短包含子串的解

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<memory.h>

const int N = 100000 ;

int main(void)
{
	int i,j,n,nBeg,nEnd,nLen,nMinLen,nSeqLen ;
	int b[N] ;
	char szStr[N] ;
	char szQueue[N] ;
	int t ;

	freopen("in.txt","r",stdin) ;
	scanf("%d",&t) ;
	while (t-- >  0)
	{
		scanf("%s",szStr) ;	
		memset(b,-1,sizeof(b)) ;
		memset(szQueue,0,sizeof(szQueue)) ;
		nBeg = nEnd = -1 ;
		nLen = strlen(szStr) ;
		n = 0 ;
		nMinLen = -1 ;

		for(i = 0 ; i < nLen ; ++i)
		{
			if(szStr[i] >= 'a' && szStr[i] <= 'c')
			{
				if(-1 == nBeg)
				{
				//	nBeg = 0 ;
					n += 1 ;
					nEnd++ ;
					nBeg = nEnd ;
					szQueue[nEnd] = szStr[i] ;
					b[szStr[i]-'a'] = nBeg  ;
				}
				else if(n >= 3 && szStr[i] == szQueue[nBeg])
				{
					nEnd++ ;
					szQueue[nEnd] = szStr[i] ;
					szQueue[b[szStr[i]-'a']] = '\0' ;
					b[szStr[i]-'a'] = nEnd ; 

					for(j = nBeg + 1 ; j < nEnd ; ++j)
					{
						if(szQueue[j] != '\0')
						{
							nBeg = j ;
							break ;
						}
					}

					nSeqLen = nEnd + 1 - nBeg ;
					if(nSeqLen < nMinLen)
					{
						nMinLen = nSeqLen ;
					}
				}
				else if(szStr[i] == szQueue[nBeg] && n < 3)
				{
					nEnd++ ;
					szQueue[nEnd] = szStr[i] ;
					szQueue[b[szStr[i]-'a']] = '\0' ;
					b[szStr[i]-'a'] = nEnd ; 

					for(j = nBeg + 1 ; j <= nEnd ; ++j)
					{
						if(szQueue[j] != '\0')
						{
							nBeg = j ;
							break ;
						}
					}
				}
				else if(b[szStr[i]-'a'] != -1)
				{
					nEnd++ ;
					szQueue[nEnd] = szStr[i] ;
					szQueue[b[szStr[i]-'a']] = '\0' ;
					b[szStr[i]-'a'] = nEnd ; 
				}
				else 
				{
					nEnd++ ;
					szQueue[nEnd] = szStr[i] ; 
					n += 1 ;
					b[szStr[i]-'a'] = nEnd ;

					if(n >= 3)
					{
						nMinLen = nEnd + 1 - nBeg ;
					}
				}
			} 
			else //排除其它字符
			{
				nEnd++ ;
				szQueue[nEnd] = '\0' ;
			}
		} 
		printf("%d\n",nMinLen) ;
	}
	return 0 ;
}







 
/*	---------------------------------------------------------------------------------
	嗯,这一道题之前想了很久也没有找到可行的解决方案,对,不是最优方案,而是可行方案。
	不知道怎么的,当时看到这一道题的时候,真的怎样想也没有想到解决方案。第一次做这一
	道题目的时候是一年前,那师兄家兄师兄推荐我去学算法~~~结果当时还审错题,以为只有
	abc三种,结果提交了很多次也WA,纠结了很久也没有做出来。后来也不了了之。
	一年后的最近,看看这一题,没有审错题,但是发现自己更加没有想法了。因为这道题貌似
	有很多种不确定因素。。不过,不记得那一天坐地铁,自己突然想都了突破口,但是还是没有
	找到可行方法。然后今天又是在地铁上想到了可行方案,那就是在这个突破口上面调整一下,
	结果就AC了~~~

	好,记记自己的大概思路:
	1、主要思路其实就是穷举字符串可能出现abc的各种组合,从而写出对应代码(所以,我的代码
		比较长,而且可读性不高。)

    初始情况:已经找到a、b、c中的第一个字符
    条件:在找到a、b、c三种字符中的其中一个的时候。

	情况1:再一次找到第一个发现的字符,此时abc中,只有一个字符被发现
	做法:更新pFirstFind指向的位置。

    情况2:再一次找到第一个发现的字符,此时abc中,已经有两个字符被发现
	做法:pFirstFind指向原来pSecondFind的位置,pSecondFind指向当前位置
		  分别对应更新chFirst,chSecond的值

    情况3:在已经发现一个字符的情况下,找到第二个字符
	做法:pSecondFind,chSecond处理之

    情况4:在已经发现两个字符的情况下,再一次找到第二个字符。
	做法:更新pSecondFind  (因为最短的字符串中间,只可能有一种发现字符)

    情况5:找到第三个字符
	做法:计算减肥后的长度,并与最小值比较,更新最小值

    嗯嗯,大概思路就是这样,先记下来,待有空的时候再优化

    AC,15MS。。代码很长,1.79K,家兄师兄的0MS,0.64K~~肿么会差这么多~~

	---------------------------------------------------------------------------------	*/

#include<stdio.h>
#include<string.h>

char	szInput[100005] ;

int main(void)
{
	int		i = 0 ;
	int		j = 0 ;
	int		n = 0 ;
	int		t = 0 ;
	int		nResult = 0 ;
	int		nFindTotal = 0 ;
	char	*pFirstFind , *pSecondFind , *pThridFind ;
	char	chFirst , chSecond , chThrid ;
	char	*pCurPos ;

	scanf("%d",&t) ;

	while(t-- > 0 ) 
	{
		scanf("%s",szInput) ;
		
		n = strlen(szInput) ;

		nFindTotal = 0 ;
		pFirstFind = pSecondFind = pThridFind = NULL ;
		chFirst = chSecond = chThrid = '\0' ;
		pCurPos = NULL ;
		nResult = 0 ;

		for(i = 0 ; i < n ; i++)
		{
			if('a' == szInput[i] || 'b' == szInput[i] || 'c' == szInput[i])
			{
				pFirstFind = szInput + i ;
				chFirst = szInput[i] ;
				break ;
			}
		}

		nFindTotal++ ;
		j = i + 1 ;

		for(i = j ; i < n ; i++)
		{
			pCurPos = &szInput[i] ;

			if('a' == szInput[i] || 'b' == szInput[i] || 'c' == szInput[i])
			{
				if(chFirst == szInput[i])
				{
					if(1 == nFindTotal)
					{
						pFirstFind = pCurPos ;
					}
					else if(2 == nFindTotal)		//之前错是这里忘记更新字符1和字符2的值了
					{
						pFirstFind = pSecondFind ;
						pSecondFind = pCurPos ;
						chFirst = chSecond ;
						chSecond = szInput[i] ;
					}
				}
				else if(1 == nFindTotal)
				{
					pSecondFind = pCurPos ;
					chSecond = szInput[i] ;
					nFindTotal++ ;
				}
				else if(2 == nFindTotal && chSecond == szInput[i])
				{
					pSecondFind = pCurPos ;
				}
				else if(nFindTotal < 3)
				{
					pThridFind = pCurPos ;
					chThrid = szInput[i] ;
					if(0 == nResult || pThridFind - pFirstFind + 1 <= nResult)
					{
						nResult = pThridFind - pFirstFind + 1 ;
					}
					pFirstFind = pSecondFind ;
					chFirst = chSecond ;
					pSecondFind = pThridFind ;
					chSecond = chThrid ;
				}
			}
		}
		printf("%d\n",nResult ) ;
	}	
	return 0 ;
}

 

 

/*	---------------------------------------------------------------------
	解法二:边输入,边处理

	问题:时间依然是15MS,原因是核心代码没有变,依然是穷举法。可能是比较
		  次数较多,所以依然很慢

	---------------------------------------------------------------------	*/

#include<stdio.h>
#include<string.h>

int main(void)
{
	int		t = 0 ;
	int		nResult = 0 ;
	int		nFindTotal = 0 ;
	int 	nFirstFind = 0 ;
	int		nSecondFind =  0 ;
	int		nThridFind = 0 ;
	char	chFirst , chSecond , chThrid ;
	int		nCurPos ;
	char	chCur= '\0' ;

	scanf("%d",&t) ;

	while(getchar() != '\n')
	{
		continue ;
	}

	while(t-- > 0 ) 
	{
		nFindTotal = 0 ;
		nFirstFind= nSecondFind = nThridFind = 0 ;
		chFirst = chSecond = chThrid = '\0' ;
		nCurPos = 0 ;
		nResult = 0 ;

		while((chCur = getchar()) != '\n' && chCur != EOF )
		{		
			if(('a' == chCur || 'b' == chCur || 'c' == chCur) && 0 == nFindTotal)
			{
				nFirstFind = nCurPos ;
				chFirst = chCur ;
				nFindTotal++ ;
				
				nCurPos++ ;
				continue ;
			}
			if('a' == chCur || 'b' == chCur || 'c' == chCur)
			{
				if(chFirst == chCur)
				{
					if(1 == nFindTotal)
					{
						nFirstFind = nCurPos ;
					}
					else if(2 == nFindTotal)		
					{
						nFirstFind = nSecondFind ;
						nSecondFind = nCurPos ;
						chFirst = chSecond ;
						chSecond = chCur ;
					}
				}
				else if(1 == nFindTotal)
				{
					nSecondFind = nCurPos ;
					chSecond = chCur ;
					nFindTotal++ ;
				}
				else if(2 == nFindTotal && chSecond == chCur)
				{
					nSecondFind = nCurPos ;
				}
				else if(nFindTotal < 3)
				{
					nThridFind = nCurPos ;
					chThrid = chCur ;
					if(0 == nResult || nThridFind - nFirstFind + 1 <= nResult)
					{
						nResult = nThridFind - nFirstFind + 1 ;
					}
					nFirstFind = nSecondFind ;
					chFirst = chSecond ;
					nSecondFind = nThridFind ;
					chSecond = chThrid ;
				}
			}
			nCurPos++ ;
		}
		printf("%d\n",nResult ) ;		
	}
	return 0 ; 
} 





抱歉!评论已关闭.