尺取法

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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值