1. 程式人生 > >尋找字串A中完全包含字串B的最短子字串

尋找字串A中完全包含字串B的最短子字串

已知兩個字串a和b。字串a的字元有可能重複,字串b中的字元不重複。

編寫一個演算法,尋找字串a的最短子字串,使得該子字串包含字串b中的所有字元。

這是一道典型的動態規劃題,有點類似程式設計之美中最短摘要生成那道題目。

可以使用兩個指標t_rear和t_front遍歷字串a。使用兩個指標rear和front記錄已發現的最短字串的邊界。

使用一個變數cnt記錄已經發現的b中的字元數。

定義一個數組tab[256]作為b中字元存在性的hash表,定義一個數組cal[256]存放已經發現的在ab中均出現的字元的個數。

1、剛開始t_rear和t_front均指向a的第一個字元。然後t_rear開始向後遍歷。

2、每當t_rear找到一個出現的在b中存在的字元,就讓cal中該字元計數加1。如果該字元第一次出現,則讓cnt也加1;

3、當cnt的數值等於b的字元個數時,t_front開始往後遍歷。當t_front發現一個在b中存在的字元時,就讓cal中的該字元計數減1。如果減1之後計數變為0,則記錄

此時t_rear和t_front的下標。如果t_rear-t_front<rear-front,則將rear和front更新為t_rear和t_front;

4、遍歷完a即可確定所求的最短子字串。

程式碼如下:

#include<iostream>
using namespace std;

void find(char a[], int Na, int tab[], int Nb);
int main()
{
	char a[]={'1', '4', '2', '3', '7', '3', '9', '3', '1', '0', '5', '7', '4', '6'};
	char b[]={'3', '9', '1'};
	int tab[256]={0};
	for(int i=0; i<3; i++)
	{
		tab[b[i]]=1;
	}
	find(a, 14, tab, 3);
	system("pause");
}

void find(char a[], int Na, int tab[], int Nb)
{
	int front=0, rear=Na-1;
	int t_front=0, t_rear=0;
	int cnt=0;
	int cal[256]={0};
	while(t_rear<Na)
	{
		if(tab[a[t_rear]])
		{
			
			cout<<a[t_rear]<<endl;
			if(cal[a[t_rear]]==0)
			{
				
				cnt++;
				//cout<<cnt<<endl;
			}
				
			cal[a[t_rear]]++;
			if(cnt==Nb)
			{
				while(t_front!=t_rear)
				{
					if(tab[a[t_front]])
					{
						cal[a[t_front]]--;
						if(cal[a[t_front]]==0)
							break;
					}
					t_front++;
				}
				if(t_rear-t_front < rear-front)
				{
					rear=t_rear;
					front=t_front;
				}
				t_front++;
				cnt--;
			}
			t_rear++;
		}
		else
			t_rear++;
	}
	for(int i=front; i<=rear; i++)
	{
		cout<<a[i]<<" ";
	}
	cout<<endl;
}