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

最小子串

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

最小子串

题目:给一个字符串s1,和一个小串s2,求算法能在s1中找到包含s2里所有字符的最小子串。比如:

    s1 = “ADOBECODEBANC”

    s2 = “ABC”

最小子串是 “BANC”,要求O(N)的算法。

分析

设置两个指针p1,p2,初始化指向s1串的开头。当p1, p2指针之间的s1子串字母包含s2全部字符时,p1++,当两个指针之间的子不完全包含s2中的全部字符时p2++(增加指针间距),与此同时记录合法包含子串的的最小串的起始位置。

在进行上述伸缩时,如何快速的记录s2串的包含情况?使用一个hash 表,记录字符的出现次数,当p1++时,将对应字母的计数减1,当p2++时,将对应字母的计数加1。

参考代码:

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

int FindMinSubString(char* s1, char* s2)
{

	int hash_table[256];

	/*
		初始化 hash 表,s2中出现的字符标记为0,
		其他标记为负数
	*/
	for (int i=0; i<256; i++)
	{
		hash_table[i] = -1;
	}

	for (char* p = s2; *p != '\0'; p++)
	{
		hash_table[*p] = 0;
	}

	char* p1 = s1;
	char* p2 = s1;

	//最短长度
	int min_len = 2100000000;

	//最小串的起止位置
	char* min_p1 = s1;
	char* min_p2 = s1;

	//记录p1 p2之间的合法字符种类数 ,count == s2_len 包含s2
	int count = 0;

	int s2_len = strlen(s2);

	/*
		注意p2到达s1的结束位置后,不能结束
		应当继续收缩,直到不含s2
	*/
	while(*p2 !='\0' || s2_len==count)
	{

		//p1...p2不包含s2
		if (count<s2_len)
		{
			//属于s2中出现的字符
			if (hash_table[*p2] == 0)
			{
				count++;
				hash_table[*p2]++;
			}
			else if (hash_table[*p2] > 0)
			{
				hash_table[*p2]++;
			}

			p2++;
		}

		//不能用else 因为在上一个if语句中对count++;
		if(count == s2_len)
		{
			if (p2-p1 < min_len)
			{
				min_p1 = p1;
				min_p2 = p2;
				min_len = p2-p1;
			}

			//收缩
			hash_table[*p1]--;
			if (hash_table[*p1] == 0)
			{
				count--;
			}
			p1++;
		}
	}

	//输出
	while(min_p1 < min_p2)
	{
		printf("%c",*min_p1);
		min_p1++;
	}

	return min_len;
}

int main()
{
	char text[] = "abckixyszdefloiadczbcdsdsadfasfdsfdfdfdsfaczb";
	char str[10];
	puts(text);
	gets(str);
	printf("%d\n", FindMinSubString(str, text));
	
}

抱歉!评论已关闭.