[leetcode]5.最长回文字符串

题目地址 https://leetcode-cn.com/problems/longest-palindromic-substring/

分析题目

题目需要找到最长回文字符串,最长这个特点可以通过max寄存器与temp值比较可得。回文字符串具有对称性的特点,对称可以找对称中心来解决。
除此之外还需要处理回文字符串长度为奇偶的情况。

算法用的是找对称中心然后从中心扩散的方法,其他的算法类似搞二维数组(太占空间了,事件复杂度也不突出)、马拉车算法(插入#时每个元素都要访问一遍,也很浪费时间)

代码与算法

初次设计的算法:从string的首个字符开始遍历,每个字符都查找一次奇数回文,一次偶数回文。

public string LongestPalindrome(string s)
    {
        int maxStringLength, tempStringLength;
        int maxStringLeft, tempStringLeft, tempStringRight;
	//max寄存器保存字符串长度和起始点就可以了,这是根据String.Substring方法决定的
	//temp记录的left和right是扩散时的左右哦指针
	
	//奇数判断开始
        maxStringLength = 1;//不可为0,因为s="ab"时输出"a"
        maxStringLeft  = 0;
        for (int i = 0; i < s.Length; i++)
        {
            tempStringLeft=tempStringRight = i;
            tempStringLength = 1;
            do
            {
                if (tempStringLength > maxStringLength)
                {
                    maxStringLength = tempStringLength;
                    maxStringLeft = tempStringLeft;
                }
                tempStringLength = tempStringLength + 2;
                tempStringLeft--;
                tempStringRight++;
                if (tempStringLeft < 0)
                    break;
                if (tempStringRight == s.Length)
                    break;
            } while (s[tempStringLeft] == s[tempStringRight]);
		//使用do-while的原因是判断字符相等时,可能会出现数组下标溢出的情况
		//所以要先判断是否溢出。
		
		//偶数判断开始

            tempStringLength = 2;//偶数判断的特殊性,需要判断下一位字符是否相等
            tempStringLeft = i ;
            tempStringRight = i + 1;
            if (i == s.Length - 1)
                continue;//判断溢出
            if (s[i] != s[i + 1])
                continue;//判断相等
            do
            {
                if (tempStringLength > maxStringLength)
                {
                    maxStringLength = tempStringLength;
                    maxStringLeft = tempStringLeft;
                }
                tempStringLength = tempStringLength + 2;
                tempStringLeft--;
                tempStringRight++;
                if (tempStringLeft < 0)
                    break;
                if (tempStringRight == s.Length)
                    break;
            } while (s[tempStringLeft] == s[tempStringRight]);
        }
        return s.Substring(maxStringLeft, maxStringLength);
    }

优化改进

上述算法将奇偶回文字符串分开判断,但写完代码后发现奇偶判断之间有比较高的耦合性,可以尝试合并。
两个判断的主要差异在于判断起始点,奇回文起始点为单个字符,偶回文起始点为两个字符。尝试将左右判断指针应用到起始点上。奇回文起始点为单个,左右判断指针同时指向这个字符,满足判断相同条件。偶回文起始点为两个,左右判断指针分别指两个字符。
改进后的代码:

public string LongestPalindrome(string s)
    {
        int maxStringLength;
        int maxStringLeft;
        maxStringLength = 1;
        maxStringLeft  = 0;
        for (int i = 0; i < s.Length; i++)
        {
            CentralSpreading(s,i,i,1,ref maxStringLength,ref maxStringLeft);
            CentralSpreading(s, i, i+1, 2, ref maxStringLength, ref maxStringLeft);
        }
        return s.Substring(maxStringLeft, maxStringLength);
    }

    public void CentralSpreading(string s,int tempStringLeft, int tempStringRight, int tempStringLength, ref int maxStringLength,ref int maxStringLeft)
    {
        while (tempStringLeft > -1 && tempStringRight < s.Length && s[tempStringLeft] == s[tempStringRight])
        {
            if (tempStringLength > maxStringLength)
            {
                maxStringLength = tempStringLength;
                maxStringLeft = tempStringLeft;
            }
            tempStringLength = tempStringLength + 2;
            tempStringLeft--;
            tempStringRight++;
        }
    }

比较两次leetcode上性能提升了10%
image

posted @ 2021-11-16 13:07  none323  阅读(34)  评论(0)    收藏  举报