zoukankan      html  css  js  c++  java
  • Longest palindrome subsequence

    问题

    来自于《Introduction to algorithm》(CLRS) Problem 15-2

    A palindrome is a nonempty string over some alphabet that reads the same forward and backward. Examples of palindromes are all strings of length 1, civic, racecar,and aibohphobia (fear of palindromes). Give an efficient algorithm to find the longest palindrome that is a subsequence of a given input string. For example, given the input character, your algorithm should return carac. What is the running time of your algorithm?

    Input

    • X = <x1, x2, .... , xm>

    Output

    • the longest palindrome of X

    调用LCS算法

    针对这个问题,完全可以使用LCS最长公共子序列问题的算法进行求解,将所给字符串A进行倒置得到字符串B,计算A,B的最长公共子序列即可。

    动态规划算法

    引用:算法导论 — 思考题15-2 最长回文子序列

    优化子结构

    Theorem

    假设P[1..k]=< p1, p2 ,…,pk> 是字符串S[1..n]=s1, s2 ,…, sn的一个最长回文子序列,那么:

    • if s1 == sn, then s1 = p1, sn = pn, P[2..k-1]是S[2..-1]的一个最长回文子序列
    • if s1 != sn, s1 != p1, then P[1..k]是S[2..k]的一个最长回文子序列
    • if s1 != sn, s1 != pn, then P[1..k]是S[1..k-1]的一个最长回文子序列

    这一问题的优化子结构,及其类似于LCS问题的优化子结构,都需要依据情况进行想处理。

    Proof

    • 如果s1 != p1(s2 != p2这两个其实是一个意思),那么,完全可以将s1,s2加在P[1..k]两侧,构造一个比当前最长回文子序列更长的回文子序列。
    • 如果P[2..k-1]不是S[2..k-1]的一个最长回文子序列,即存在回文子序列Q是S[2..k-1]的一个最长回文子序列,且,|Q| > k-2。那么,可以在Q两端加入s1==sn,得到回文子序列M,|M| > k,这与P[1..k]=< p1, p2 ,…,pk> 是字符串S[1..n]=s1, s2 ,…, sn的一个最长回文子序列矛盾,假设不成立。
    • 至于2&&3点,反证法及其简单。

    递归地定义代价方程

    定义c[i,j ]为s[i,j] = <si, si+1,..., sj>的最长回文子序列的长度。

    [c[i,j]= left{ egin{array}{rcl} & 0 & j < i \ & 1 & j = i \ & c[i+1,j-1] & j>i,s_{i} = s_{j} \ & max{c[i,j-1],c[i+1,j]} & j>i,s_{i} eq s_{j} end{array} ight. ]

    重叠子问题

    要计算 需计算 需计算 需计算
    c[i,j] c[i+1,j-1] c[i,j-1] c[i+1,j]
    c[i+1,j-1] c[i+2,j-2] c[i+1,j-2] c[i+2,j-1]
    c[i,j-1] c[i+1,j-2] c[i,j-2] c[i+1,j-1]
    c[i+1,j] c[i+2,j+1] c[i+1,j-1] c[i+2,j]

    计算优化解的代价的伪代码

    下图为优化解的填充顺序,黄》绿》蓝》橘》灰》白

    image-20201010150927028

    由此可以构建出计算优化解的算法(bottomup):

    LPS_LENTH(x)
    n = x.length
    let s[1..n,1..n] and c[1..n,1..n]be a new array
    for i = 1 to n do
        s[i,i] = 1; 
        s[i,i-1] = 0;
    for l = 1 to n - 1 do 
        for i = 1 to n - l
            j = i + l
            if xi == xj
                s[i,j] = s[i+1,j-1] + 2
                c[i,j] = '↙'
            else 
                if s[i+1,j] > s[i,j-1]
                   s[i,j] = s[i+1,j]
                   c[i,j] = '↓'
                else
                   s[i,j] = s[i,j-1]
                   c[i,j] = '←'
    

    构造优化解的伪代码

    Print_LPS(x,c,i,j)
    if i == j 
        print x[i]
        return
    if c[i,j] == '↙'
        print x[i];
        Print_LPS(x,c,i+1,j-1);
        print x[i];
    else if c[i,j] == '↓'
        Print_LPS(x,c,i+1,j);
    else if c[i,j] = '←'
        Print_LPS(x,c,i,j-1);
    

    算法复杂度分析

    计算优化解的代价的算法时间复杂度为:O(n2)

    构造优化解算法的时间复杂度为:O(n)

    代码

    #include<stdio.h>
    #include<string.h>
    
    #define N 9
    
    void LPS_LENGTH(char* x);
    void Print_LPS(char* x, char c[N + 1][N + 1], int i, int j);
    
    void main() {
    	char x[N + 1] = { ' ', 'c', 'h', 'a', 'r', 'a', 'c', 't','e','r' };
    	for (int i = 1; i <= N; i++) {
    		printf("%c	", x[i]);
    	}
    	printf("
    ");
    	
    	LPS_LENGTH(x);
    
    }
    
    void LPS_LENGTH(char* x) {
    	int s[N + 1][N + 1];
    	char c[N + 1][N + 1];
    	memset(s, 0, sizeof(int) * (N + 1) * (N + 1));
    	memset(c, '0', sizeof(char) * (N + 1) * (N + 1));
    	for (int i = 1; i <= N; i++) {
    		s[i][i] = 1;
    		s[i][i - 1] = 0;
    	}
    	for (int l = 1; l <= N - 1; l++) {
    		for (int i = 1; i <= N - l; i++) {
    			int j = i + l;
    			if (x[i] == x[j]) {
    				s[i][j] = s[i + 1][j - 1] + 2;
    				//c[i][j] = '↙';
    				c[i][j] = '1';
    			}
    			else {
    				if (s[i + 1][j] > s[i][ j - 1]) {
    					s[i][j] = s[i + 1][j];
    					//c[i][j] = '↓';
    					c[i][j] = '2';
    				}
    				else {
    					s[i][j] = s[i][j - 1];
    					//c[i][j] = '←';
    					c[i][j] = '3';
    				}
    			}
    		}
    	}
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++)
    			printf("%d	", s[i][j]);
    		printf("
    ");
    	}
    	printf("
    ");
    	printf("
    ");
    	for (int i = 1; i <= N; i++) {
    		for (int j = 1; j <= N; j++)
    			printf("%d	", s[i][j]);
    		printf("
    ");
    	}
    	printf("
    ");
    	printf("
    ");
    	Print_LPS(x, c, 1, N);
    }
    
    void Print_LPS(char *x, char c[N+1][N+1], int i, int j) {
    	if (i == j) {
    		printf("%c	", x[i]);
    		return;
    	}
    	if (c[i][j] == '1') {
    		printf("%c	", x[i]);
    		Print_LPS(x, c, i + 1, j - 1);
    		printf("%c	", x[i]);
    	}
    	else if(c[i][j] == '2')
    		Print_LPS(x, c, i + 1, j);
    	else 
    		Print_LPS(x, c, i, j - 1);
    }
    
  • 相关阅读:
    OpenCV图片类cv::Mat和QImage之间进行转换(好多相关文章)
    在 .pro里加入 QMAKE_CXXFLAGS += /MP 将并行编译(VC),加快编译速度(姚冬的办法),或者-j4参数(MinGW)
    GUI为什么不设计为多线程(用户事件和底层事件的流程是相反的,每层都加锁效率太低,共用一把锁那就是单线程)
    QML的渲染方式相较于之前的版本也有了重大的更新(CPU线程负责绘制,GPU线程负责渲染),还有好多经常评论 good
    分析Sizzle引擎
    当Azure里的虚拟机网卡被禁用
    SQL Server跨网段(跨机房)FTP复制
    公众平台Bee.WeiXin
    使用Jquery+EasyUI进行框架项目开发案例讲解之一---员工管理源码分享
    阿里巴巴笔试
  • 原文地址:https://www.cnblogs.com/zqybegin/p/13810750.html
Copyright © 2011-2022 走看看