`
gwmwhu
  • 浏览: 63243 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
社区版块
存档分类
最新评论

最长公共子序列

阅读更多

今天实现的算法是求解最长公共子序列,在字母表Σ上,分别给出两个长度为n和m的字符串A和B,确定在A和B中最长公共子序列的长度并输出该最长公共子序列。这里,A=a1a2...an的子序列是一个形式为ai1ai2...aik的字符串,其中每个ij都在1和n之间,并且1<=i1<i2<...<ik>=n,子序列不是子串,并不要求连续。例如zxyxyz和xyyzx的最长公共子序列为xyyz。

此问题可以用动态规划技术来解决,为了使用动态规划,首先得有一个递推公式。令A = a1a2...an好B = b1b2...bn,令L[i,j]表示a1a2...ai和b1b2...bi的最长公共子序列的长度。i、j可能为0,即表示空串。则i=0或j=0时,L[i,j]=0。递推关系如下:

如果i和j都大于0,那么

 

  • 若ai = bj,L[i,j] = L[i-1,j-1]+1
  • 若ai ≠ bj,L[i,j] = max{L[i,j-1],L[i-1,j]}
根据上述递推关系可以导出如下的算法:
算法:LCS
输入:字符串A和B,长度分别为n和m
输出:A和B最长公共子序列的长度和其中一个最长公共子序列
for i ← 0 to n:
    L[i,0] ← 0
end for
for j ← 0 to n:
    L[0,j] ← 0
end for
for i ← 1 to n:
    for j ← 1 to m:
        if ai == bi then L[i,j] ← L[i-1,j-1] + 1
        else L[i,j] ← max{L[i,j-1],L[i-1,j]}
        end if
    end for
end for
while i <= n and j <= m:
    if ai == bi then 输出ai i=i+1 j=j+1
    else if L[i+1,j] > L[i][j+1] then i = i+1
    else j = j+1
end while
return L[n,m]
 
下面是C++版本的实现:
//main.cpp
#include <iostream>
#include "LCSString.h"

using std::cout;
using std::endl;

int main(void) {
	LCSString s1("xyxxzxyzxy");
	std::string s2("zxzyyzxxyxxz");

	std::string s = s1.getLCS(s2);

	cout << s1 << "和" << s2 << "的一个最长公共子序列为:";
	cout << s << endl;

	getchar();
	return 0;
}
 

 

//LCSString.h
#pragma once
#include <string>

class LCSString:public std::string {
public:
	LCSString(void);
	LCSString(const char * _Ptr);
	~LCSString(void);
	std::string getLCS(std::string s);
};

 

 

//LCSString.cpp
#include "LCSString.h"
#include <iostream>
using std::cout;
using std::endl;

LCSString::LCSString(void):std::string() {
}

LCSString::LCSString(const char * _Ptr):std::string(_Ptr) {
}

LCSString::~LCSString(void) {
}

//求本字符串与另一个字符串s的最长公共子序列
std::string LCSString::getLCS(std::string s) {
	std::string result;
	int n_len = this->length()+1;
	int m_len = s.length()+1;
	int ** L = new int * [n_len];
	for (int i = 0; i < n_len; i++) {
		L[i] = new int [m_len];
	}

	for (int i = 0; i < n_len; i++) {
		L[i][0] = 0;
	}
	for (int i = 0; i < m_len; i++) {
		L[0][i] = 0;
	}
	for (int i = 1; i < n_len; i++) {
		for (int j = 1;j < m_len; j ++) {
			if (this->operator[](i-1) == s[j-1]) {
				L[i][j] = L[i-1][j-1] + 1;
			} else {
				//L[i][j]取L[i][j-1]和L[i-1][j]的最大值
				L[i][j] = (L[i][j-1] > L[i-1][j]?L[i][j-1]:L[i-1][j]);	
			}
		}
	}

	for (int i = 0; i < n_len; i++) {
		for (int j = 0; j < m_len; j++) {
			cout << L[i][j] << "  ";
		}
		cout << endl;
	}

	int i = n_len - 1;
	int j = m_len - 1;
	while (i > 0 && j > 0) {
		if (this->operator[](i-1) == s[j-1]) {
			result = s[j-1] + result; 
			i --;
			j --;                                                       
		} else if (L[i-1][j] == L[i][j-1]) {
			i --;
		} else {
			j --;
		}
	}

	for (int i = 0; i < n_len; i++) {
		delete [] L[i];
	}
	delete [] L;
	
	return result;
}
 

下面是Java版本实现:

 

package lcs;

public class LCSString {
	private String s1;
	
	public LCSString(String s) {
		this.s1 = new String(s);
	}
	
	public String getLCSString(String s2) {
		String result = new String();
		int n = s1.length()+1;
		int m = s2.length()+1;
		int [][] L = new int [n][m];
		for (int i = 0; i < n; i++) {
			L[i][0] = 0;
		}
		for (int i = 0; i < m; i++) {
			L[0][i]= 0; 
		}
		for (int i = 1; i < n; i++) {
			for (int j = 1; j < m; j++) {
				if (s1.charAt(i-1) == s2.charAt(j-1)) {
					L[i][j]= L[i-1][j-1] + 1; 
				} else {
					//L[i][j]取L[i][j-1]和L[i-1][j]的最大值  
	                L[i][j] = (L[i][j-1] > L[i-1][j]?L[i][j-1]:L[i-1][j]); 
				}
			}
		}
		int i = n - 1;
		int j = m - 1;
	
		while (i > 0 && j > 0) {
			if (s1.charAt(i-1) == s2.charAt(j-1)) {
				result = s1.charAt(i-1) + result; 
				i --;
				j --;                                                       
			} else if (L[i-1][j] == L[i][j-1]) {
				i --;
			} else {
				j --;
			}
		}
		
		return result;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s1 = "xyxxzxyzxy";
		String s2 = "zxzyyzxxyxxz";
		LCSString lcs = new LCSString(s1);
		System.out.println(s1 + "和" + s2 + "的一个最长公共子序列为:" + lcs.getLCSString(s2));
	}

}

 

下面是Python版本实现:

 

#! /usr/bin/env python
# -*- coding:utf-8 -*-

class LCSString:
    def __init__(self, s):
        self.s1 = str(s)

    def getLCSString(self, s2):
        result = ''
        n = len(self.s1)+1
        m = len(s2)+1
        L = [0]*n
        for i in range(0, n):
            L[i] = [0] * m

        for i in range(1, n):
            for j in range(1, m):
                if self.s1[i-1] == s2[j-1]:
                    L[i][j] = L[i-1][j-1] + 1
                else:
                    L[i][j] = max(L[i-1][j], L[i][j-1])
        
        print
        for i in L:
            for j in i:
                print j,
            print
        i = n-1
        j = m-1
        while i > 0 and j > 0:
            if self.s1[i-1] == s2[j-1]:
                result = s2[j-1] + result
                i -= 1
                j -= 1
            elif L[i-1][j] == L[i][j-1]:
                i -= 1
            else:
                j -= 1
        
        return result

if __name__ == '__main__':
    s1 = "xyxxzxyzxy"
    s2 = "zxzyyzxxyxxz"
    lcs = LCSString(s1)
    print s1 + "和" + s2 + "的一个最长公共子序列为:" + lcs.getLCSString(s2)

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics