• 寻找最长回文字符串


    首先讲解一种简单容易理解的暴力解法:复杂度为O(n^2)

    解题思路是:第一,定义一个pStr指向字符串str,再定义一个p指向pStr,q指向pStr+1;

    第二,找出一个字符*p与其下一个字符*q相同位置,比如oo,num++,index = p;然后比较这两个相同字符*p,*q两边的字符是否相等,如果相等再向两边扩展p--,q++(p>str&&q!='')。如果p指向首部,即p=str,则调出while循环,再比较一次if(*p == *q),num++,index = q.

    第三,如果发现连续两个字符不相等,则让pStr++,p=pStr,q =pStr+1.

    第四,通过maxNum和maxIndex记录下最长回文的数目和位置。

    #include <iostream>
    using namespace std;
    
    void GetLongestSymmetricalLength(char* str)
    {
        if(str==NULL)
            return;
    
        char* pStr = str;
        char* p = pStr;
        char* q = pStr+1; 
        int num=0;
        int maxNum=0;;
        char* index = pStr;
        char* maxIndex = index;
    
        while(*pStr != '')
        {
            while((*p != *q))
            {
                num = 0;
                pStr++;
                p = pStr;
                q = pStr+1;
            }
            while((*p == *q)&&(p > str)&&(*q != ''))
            {
                num++;
                index = p;
                p--;
                q++;
            }
            if((p == str)&&(*p == *q)&&(*q != ''))
            {
                num++;
                index = p;
            }
    
            if(num > maxNum)
            {
                maxNum = num;
                maxIndex = index;
            }
    
            pStr++;
            p = pStr;
            q = pStr+1;
        }
        cout << "Result: " ;
        for(int i=0;i<2*maxNum;++i)
            cout << *maxIndex++ << " ";
        cout << endl;
        cout << "maxNum: "  << maxNum << endl;
    }
    
    int main()
    {
        char* str = "abbacaacab";
        GetLongestSymmetricalLength(str);
    
        return 0;
    }
    

      

    以下空间复杂度和时间复杂度均为O(n)

    思路:

    复杂度为O(n),即指遍历一遍数组,因而必须创建一数组保存已走过字符的长度信息(之前每个字符的最长回文串)。

    同时,如”aba“最长回文长度为3,中心为’b';”aa“最长回文长度为2,中心却是两字符中心,如此在统计长度时,需对奇偶串长分别比较,有什么办法使其统一吗?——插入特殊字符,如‘#’,”aba“为”#a#b#a#“,”aa“为”#a#a#“,如此,奇偶情况的最长长度都分别有了对应的中心。具体如下:

    1 、在各个字符间插入特殊字符‘#',将字符S转换为T,如S = “abaaba", T = "#a#b#a#a#b#a#”。

    2、定义数组P[length],其中P[i]表示以Ti为中心的最长回文长度的一半(因为T添加了字符’#‘,故其一般即为S中最长回文子串,也即Ti最长边界到Ti的距离)

    如:

    T = # a # b # a # a # b # a #

    P = 0 1 0 3 0 1 6 1 0 3 0 1 0

    P中最长的长度为6,而6即为S的最长回文子串。显然,当长度为偶数时,在T中对应的是’#‘;为奇数时,对应的是原有字符,这也就是为何要添加附加字符的原因——统一奇偶情况。

    下面问题的关键即为如何得到P数组。

    假设现在已经遍历到i = 13的位置,原字符串S的最长回文长度在T中对应位置C = 11,对应原字符串S的长度为9,字符串为”abcbabcba“。C的两边界分别为L = 2,R = 20;i关于C对应的位置为i' = 9。现在如何确定P[i]的大小呢?

    图中,i'下方的绿色实线表明了关于i'为中心的左右边界,又i'边界被包含在L、R之间,故i下方的绿色实线区域也一定是对称的。(即i'、i以C对称,i'为中心的长度边缘小于边界L、R,则P[i] = P[i']),令P[i] = p[i'] = 1。

    下面讨论另一种情况(即i'、i以C对称,i'为中心的长度边缘超出边界L或R),如下图

    假设现在已经遍历到i = 15的位置,原字符串S的最长回文长度在T中对应位置C = 11,对应原字符串S的长度为9,字符串为”abcbabcba“。C的两边界分别为L = 2,R = 20;i关于C对应的位置为i' = 7。

    图中绿色实线表示i、i'为中心在边界L、R内一定对称的区域;红色实线表示超出边界L、R可能无法保证i对称的区域;绿色虚线表示横跨C的区域。

    显然,我们只能判定绿色实线部分一定对称,即P[i] >= 5,但余下部分是否匹配我们则需要一一比较。

    综上,得出以下结论:

    if P[ i’ ] ≤ R – i,
    then P[ i ] ← P[ i’ ]
    else P[ i ] ≥ P[ i’ ]. (Which we have to expand past the right edge (R) to find P[ i ].

    剩下一步更新C的位置则变得容易,当当前位置i的边界超过原有R则需要更新,即

    if P[i] + i > R

      C = i;

      R = i + P[i].

    class Solution
    {
    	public:    //88 / 88 test cases passed.    //Runtime: 18 ms        
    	string longestPalindrome(string s) 
    	{       
    		if (s.size() < 2) 
    		{           
    			return s;       
    		}                //将字符串变为需要的形式       
    		string pStr;   
    		for (int i = 0; i < s.size(); ++i) 
    		{         
    			pStr.push_back('#');       
    			pStr.push_back(s[i]);     
    		}      
    		pStr.push_back('#');                //寻找回文    
    		int length = (int)pStr.size();    
    		int *arrIndex = new int[length];//每个下标对应的回文长度,P    
    		int mid = 0;//回文子串的中心位置,C    
    		int mx = 0;//回文子串的边界,R     
    		int maxIndex = 0;      
    		int maxLength = 0;            
    		for (int i = 0; i < length; ++i)
    		{       
    			arrIndex[i] = 0;      
    			int mirror = (mid << 1) - i;//i关于中心的对称位置,i'      
    			if (mx > i) 
    			{//是否超出边界            
    				arrIndex[i] = (arrIndex[mirror] < mx - i) ? arrIndex[i] : mx - i;  
    			}      
    			while ((i + arrIndex[i] + 1) < length && (i - arrIndex[i] - 1) >= 0 && pStr[i + arrIndex[i] + 1] == pStr[i - arrIndex[i] - 1]) 
    			{            
    				++arrIndex[i];     
    			}       
    			if (arrIndex[i] + i > mx) 
    			{//如果边缘超出了当前,需要更新         
    				mid = i;         
    				mx = i + arrIndex[i];     
    			}       
    			if (arrIndex[i] > maxLength) 
    			{           
    				maxLength = arrIndex[i];       
    				maxIndex = (i - 1) >> 1;  
    			}    
    		}      
    		delete[] arrIndex;         
    		string outputStr(s, maxIndex - (maxLength - 1)/2, maxLength);    
    		return outputStr;   
    	}
    };
    

      

  • 相关阅读:
    MATLAB计算机视觉与深度学习实战
    硬件创业:从产品创意到成熟企业的成功路线图
    Xcode5 创建模板和UIView 关联XIB
    iOS Development: Proper Use of initWithNibName:bundle: Affects UITableViewController
    自定义UIViewController与xib文件关系深入分析
    UIViewController XIB/NIB加载过程
    ios多视图开发中:xib与UIViewController的关联
    UIAlertView、UIActionSheet兼容iOS8
    Xcode6中怎么添加空工程模板
    [OC Foundation框架
  • 原文地址:https://www.cnblogs.com/wuyepeng/p/9735825.html
Copyright © 2020-2023  润新知