43. 百度面试题:最长公共子序列

题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中, 则字符串一称之为字符串二的子串。

注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。
请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子串,
则输出它们的长度4,并打印任意一个子串。


分析:求最长公共子串(Longest Common Subsequence, LCS)是一道非常经典的动态规划题,

先介绍LCS问题的性质:记Xm={x0, x1,…xm-1}和Yn={y0,y1,…,yn-1}为两个字符串,而Zk={z0,z1,…zk-1}是它们的LCS,则:

1.       如果xm-1=yn-1,那么zk-1=xm-1=yn-1,并且Zk-1是Xm-1和Yn-1的LCS;
2.       如果xm-1≠yn-1,那么当zk-1≠xm-1时Z是Xm-1和Y的LCS;
3.       如果xm-1≠yn-1,那么当zk-1≠yn-1时Z是Yn-1和X的LCS;


根据分析,我们可以很好的写出一个递归的算法实现。


实现如下:

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<vector>
#include<iterator>

using namespace std;

int printLCS_num(char *str1, const int len1, char *str2, const int len2, vector<char>& outstr)
{
	int num = 0;
	if(len1 <= 0 || len2 <= 0)
		return 0;
	vector<char> outstr1, outstr2;
	if(str1[len1-1] == str2[len2-1])
	{
		num ++;
		outstr.push_back(str1[len1-1]);
		return num + printLCS_num(str1,len1-1, str2, len2 -1, outstr);
	}
	
	int num1 = printLCS_num(str1, len1-1, str2, len2, outstr1);
	int num2 = printLCS_num(str1, len1, str2, len2-1, outstr2);
	if(num1 < num2)
	{
		copy(outstr2.begin(), outstr2.end(), back_inserter(outstr));
		return num2;
	}
	else
	{
		copy(outstr1.begin(), outstr1.end(), back_inserter(outstr));
		return num1;
	}
}

int main()
{
	char* str1 = "BDCABA";
	char* str2 = "ABCBDAB";
	vector<char> vecout;
	int LCS_len = printLCS_num(str1, strlen(str1), str2, strlen(str2), vecout);
	cout <<endl <<  str1 << " and " << str2 << "'s LCS len: " << LCS_len << endl;
	ostream_iterator<char> ofile(cout, "");
	copy(vecout.rbegin(), vecout.rend(), ofile);
	cout << endl;	
	return 0;
}

输出:

./test 

BDCABA and ABCBDAB's LCS len: 4
BDAB


也可以不使用递归的求法,使用循环求解(@v_july_v):

#include "string.h"
// directions of LCS generation
enum decreaseDir {kInit = 0, kLeft, kUp, kLeftUp};
/
// Get the length of two strings' LCSs, and print one of the LCSs
// Input: pStr1         - the first string
//        pStr2         - the second string
// Output: the length of two strings' LCSs
/
int LCS(char* pStr1, char* pStr2)
{
      if(!pStr1 || !pStr2)
            return 0;
      size_t length1 = strlen(pStr1);
      size_t length2 = strlen(pStr2);
      if(!length1 || !length2)
            return 0;
      size_t i, j;
      // initiate the length matrix
      int **LCS_length;
      LCS_length = (int**)(new int[length1]);
      for(i = 0; i < length1; ++ i)
            LCS_length[i] = (int*)new int[length2];
      for(i = 0; i < length1; ++ i)
            for(j = 0; j < length2; ++ j)
                  LCS_length[i][j] = 0;
 
      // initiate the direction matrix
      int **LCS_direction;
      LCS_direction = (int**)(new int[length1]);
      for( i = 0; i < length1; ++ i)
            LCS_direction[i] = (int*)new int[length2];
      for(i = 0; i < length1; ++ i)
            for(j = 0; j < length2; ++ j)
                  LCS_direction[i][j] = kInit;
      for(i = 0; i < length1; ++ i)
      {
            for(j = 0; j < length2; ++ j)
            {
                  if(i == 0 || j == 0)
                  {
                        if(pStr1[i] == pStr2[j])
                        {
                              LCS_length[i][j] = 1;
                              LCS_direction[i][j] = kLeftUp;
                        }
                        else
                              LCS_length[i][j] = 0;
                  }
                  // a char of LCS is found, 
                  // it comes from the left up entry in the direction matrix
                  else if(pStr1[i] == pStr2[j])
                  {
                        LCS_length[i][j] = LCS_length[i - 1][j - 1] + 1;
                        LCS_direction[i][j] = kLeftUp;
                  }
                  // it comes from the up entry in the direction matrix
                  else if(LCS_length[i - 1][j] > LCS_length[i][j - 1])
                  {
                        LCS_length[i][j] = LCS_length[i - 1][j];
                        LCS_direction[i][j] = kUp;
                  }
                  // it comes from the left entry in the direction matrix
                  else
                  {
                        LCS_length[i][j] = LCS_length[i][j - 1];
                        LCS_direction[i][j] = kLeft;
                  }
            }
      }
      LCS_Print(LCS_direction, pStr1, pStr2, length1 - 1, length2 - 1);
      return LCS_length[length1 - 1][length2 - 1];
}
 
/
// Print a LCS for two strings
// Input: LCS_direction - a 2d matrix which records the direction of 
//                        LCS generation
//        pStr1         - the first string
//        pStr2         - the second string
//        row           - the row index in the matrix LCS_direction
//        col           - the column index in the matrix LCS_direction
/
void LCS_Print(int **LCS_direction, 
                    char* pStr1, char* pStr2, 
                    size_t row, size_t col)
{
      if(pStr1 == NULL || pStr2 == NULL)
            return;
      size_t length1 = strlen(pStr1);
      size_t length2 = strlen(pStr2);
      if(length1 == 0 || length2 == 0 || !(row < length1 && col < length2))
            return;
      // kLeftUp implies a char in the LCS is found
      if(LCS_direction[row][col] == kLeftUp)
      {
            if(row > 0 && col > 0)
                  LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col - 1);
            // print the char
            printf("%c", pStr1[row]);
      }
      else if(LCS_direction[row][col] == kLeft)
      {
            // move to the left entry in the direction matrix
            if(col > 0)
                  LCS_Print(LCS_direction, pStr1, pStr2, row, col - 1);
      }
      else if(LCS_direction[row][col] == kUp)
      {
            // move to the up entry in the direction matrix
            if(row > 0)
                  LCS_Print(LCS_direction, pStr1, pStr2, row - 1, col);
      }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值