http://blog.chinaunix.net/uid-24922718-id-4848418.html
这个博客说的很详细。其实质就是:在一段已知序列中找到一串符合条件的最小的序列。将复杂度降低到了O(n),已经是最快的算法了。这里有一个实例。
Description
基因序列通常是由A,C,G,T 四种碱基组成。现有一个长度为
N 的基因序列(保证N 是4 的倍数)。现希望能够只对基因序列中
的一段进行修改,使得整个基因序列中的A,C,G,T 四种碱基的
数目相同。请你帮忙算出满足这样要求的基因段最短的长度。
Input
第一行为组数T (T <= 5)。
接下来 T 行,每行输入一个仅包含 A,C,G,T 的字符串。
字符串长度 <= 3*100000
Output
对于每组输入,输出一个数表示最短的基因段的长度。
Sample Input
2
AGGGTAAA
AGCC
Sample Output
4
1
运用尺取法,从第一个元素开始读取,然后进行判断。判断的条件是 覆盖区域 外的每种元素数量 是否大于平均值(N/4)。
如果不满足,则读取下一个元素。若满足则将最后一个元素踢出去,然后再进行判断。
当我们把大致框架画出来后,可以发现,判断是一个核心程序。 在判断过程中(满足的情况下)还掺杂有判断,暗示着我们要用递归。
详细代码如下
#include<stdio.h>
#include<string.h>
int judge(char*A,char*B,int *cnt,int ave,int k,int* val,int *len)
{
for(int i=0;i<4;i++)
if(cnt[i] > ave) return 1;
for(int i=0;i<4;i++)
if(A[k-*val] == B[i]){ cnt[i]++; break;}
if(*val < *len) *len = *val;
(*val)--; //!!必须要加括号,否则不起作用
if( judge(A,B,cnt, ave, k, val, len) ) return 1;
}
int main()
{
char B[] = {'A','C','G','T'};
char A[300000+10];
int cnt[4] = {0};
int T;
scanf("%d",&T);
while(T--){
int val = 0;
memset(A,0,sizeof(A));
memset(cnt,0,sizeof(cnt));
scanf("%s",A);
int ave = strlen(A)/4;
for(int i=0;i<strlen(A);i++){
for(int j=0;j<4;j++)
if(A[i] == B[j]) cnt[j]++;
}
//loop
int k=0;
int len =strlen(A);
while(judge(A,B,cnt, ave, k, &val,&len) && k < strlen(A)){
val++;
for(int i =0;i<4;i++)
if(A[k] == B[i]){ cnt[i]--; break;}
k++;
}
printf("%d\n",len);
}
return 0;
}
1961

被折叠的 条评论
为什么被折叠?



