1. 程式人生 > >求最長公共子序列

求最長公共子序列

ade empty 全部 str2 comm star 要求 longest strlen

最長公共子序列,英文縮寫為LCS(Longest Common Subsequence)。其定義是。一個序列 S 。假設各自是兩個或多個已知序列的子序列。且是全部符合此條件序列中最長的。則 S 稱為已知序列的最長公共子序列。而最長公共子串(要求連續)和最長公共子序列是不同的。




#include "stdafx.h"
#include<deque>
#include<iostream>

using namespace std;

deque<pair<char, int>>common;
deque<pair<char, int>>max;
deque<deque<pair<char, int>>>aa;
int k = 0;//在str2中找到obj的位置
int kk;



deque<pair<char, int>>char2vec(char*str, int offset)
{
	deque<pair<char, int>>aa;
	while (*str != ‘\0‘)
	{
		aa.push_back(pair<char, int>(*str, offset));
		str++;
		offset++;
	}
	return aa;
}

int find_char(char obj, char*str, int startpos)
{
	int len = strlen(str);
	while (startpos < len)
	{
		if (str[startpos] == obj)
			return startpos;
		startpos++;
	}
	return -1;
}


void forward(char*str1, char*str2, int n)
{
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	while (n < len1&&k < len2 - 1)
	{
		kk = find_char(str1[n], str2, k);
		if (kk >= 0)
		{
			common.push_back(pair<char, int>(str1[n], kk));
			k = kk;
			//if (n<len1 - 1)
			aa.push_back(char2vec(str1 + n + 1, n + 1));
		}
		n++;
	}
}


void LMS(char*str1, char*str2)
{
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	if (len1 > len2)
	{
		char*temp = str1;
		str1 = str2;
		str2 = temp;
		int tt = len1;
		len1 = len2;
		len2 = tt;
	}
	int maxlen = 0;
	int n = 0;//str1的索引

	forward(str1, str2, n);
	if (common.size() > maxlen)
	{
		maxlen = common.size();
		max = common;
	}
	while (!aa.empty())
	{
		if (aa.back().empty())
		{
			aa.pop_back();
			common.pop_back();
			if (aa.empty())
				return;
		}
		if (common.size() > 1)
		{
			k = common[common.size() - 2].second + 1;
		}
		else
		{
			k = 0;
		}
		kk = find_char(aa.back().front().first, str2, k);
		if (kk >= 0)
		{
			common.pop_back();
			common.push_back(aa.back().front());
			common.back().second = kk;//find_char(common.back().first, str2, common[common.size() - 2].second + 1);
			k = kk;
			n = aa.back().front().second;
			aa.back().pop_front();
			forward(str1, str2, n + 1);
			if (common.size() > maxlen)
			{
				maxlen = common.size();
				max = common;
			}
		}
		else
		{
			aa.back().pop_front();
			if (aa.back().empty())
			{
				aa.pop_back();
				common.pop_back();
			}

		}
	}

}



int _tmain(int argc, _TCHAR* argv[])
{
	char*str1 = "adecfbaf";
	char*str2 = "deabcabaf";

	LMS(str1, str2);
	for (int i = 0; i < max.size(); i++)
		cout << max[i].first << endl;
	system("pause");
	return 0;
}

上述算法中common中存放當前找到的子序列。common裏的pair<char,int>裏的int代表這個字符在str2中的位置。

aa中存放的是未被遍歷過的字符,aa裏的pair<char,int>裏的int代表這個字符在str1中的位置。

整個搜索過程是波浪式前進,common找到一個起點,走到結尾,然後替換common的結尾,再往前走。走到結尾再替換

重復運行。過程中記錄common的最大長度就可以




求最長公共子序列