1. 程式人生 > >題目:最長回文子串(C++)

題目:最長回文子串(C++)

ptr 這位 優化 png 技術分享 ring tdi xen 回文

看到這個題第一反應是做過啊,然後就開始寫,等寫完一測。emmmmm,原來是最長回文子串不是最長回文子序列,但是寫都寫了,我就把代碼稍微修改了一下讓適應於該題目,代碼如下:

static const auto io_speed_up = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return 0;
}();

class Solution {
public:
    string longestPalindrome(string s) 
    {
        int n     = s.length();
        
if (n == 1 || n == 0) return s; int max = 0; int begin = 0; vector<vector<int> > dp(n,vector<int>(n)); for (int j = 0; j < n; j++) { dp[j][j] = 1; for (int i = j - 1; i >= 0; i--) {
if (s[i] != s[j]) continue; if (dp[i + 1][j - 1] == 0 && i != j - 1) continue; dp[i][j] = dp[i + 1][j - 1] + 2; if (max >= dp[i][j]) continue; max = dp[i][j]; begin
= i; } } if (max == 0) return s.substr(begin, 1); else return s.substr(begin, max); } };

然後這個代碼一看就很搓啊,完全不適應該題,猜測效率一定很低,等提交過後看,果不其然,只超過了13.74%的代碼。只好刪了重寫。

第二次寫的代碼效率超過了32.9%代碼如下:

static const auto io_speed_up = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return 0;
}();

class Solution {
public:
    string longestPalindrome(string s) 
    {
        int n = s.length();
        if (n == 1 || n == 0)
            return s;
        int max      = 0;
        int diff     = 0;
        int begin    = 0;
        int end      = 0;
        int maxBegin = 0;
        int maxEnd   = 0;
        for (int i = 0; i < n; ++i)
        {
            for (int j = n - 1; j > 0; --j)
            {
                if (max > j - i)
                    break;
                begin = i;
                end   = j;
                while (s[begin] == s[end] && begin <= end)
                {
                    ++begin;
                    --end;
                }
                if (end < begin && begin - end < 3)
                {
                    diff = j - i;
                    if (max < diff)
                    {
                        max      = diff;
                        maxBegin = i;
                        maxEnd   = j;
                    }
                }
            }
            if (max > n - i - 1)
                break;
        }
        return s.substr(maxBegin, max + 1);
    }
};

好吧我感覺這個應該是我能想出來的最優解法了,之後我看了一下網站上的解法。其中

倒數第二個的解法是這樣的

class Solution {
public:
    string longestPalindrome(string s) {
        int len   = 0;
        int left  = 0;
        int right = 0;
        string result = "";

        int i = 0;
        while(i < s.size())
        {
            left  = i;
            right = i;
            while (right + 1 < s.size() && s[right] == s[right + 1]) 
                right++;
            i = right + 1;
            while (left >= 0 && right < s.size() && s[left] == s[right]) 
            { 
                left--; 
                right++; 
            }
            if (len < right - left - 1)
            {
                len    = right - left - 1;
                result = s.substr(left + 1, len);
            }
        }

        return result;
    }
};

厲害了我的哥,你沒優化輸入輸出流,然後在求結果字符串時還多次分割影響效率,竟然能達到6ms執行速度排第二。

我看了這位大神的代碼,發現主要思路是從一個中心下標開始向兩邊檢測,然後這裏他用了一個巧妙得方法來處理偶數長度字符串要從兩個字符開始的情況,即,選定中心後,循環檢測之後的字符是否與選定的字符相等如果相等,則+1。這樣如果出現偶數長度的字符串,開始時left和right指向相鄰的兩個字符。我把這個大神代碼加了一下速,然後丟到了leetcode上檢測,修改後的代碼如下:

static const auto io_speed_up = []()
{
    std::ios::sync_with_stdio(false);
    cin.tie(nullptr);
    return 0;
}();

class Solution {
public:
    string longestPalindrome(string s) 
    {
            int len = 0;
    int left = 0;
    int right = 0;
    int maxRes = 0;
    int leftRes = 0;

    int i = 0;
    while(i < s.size())
    {
        left = i;
        right = i;
        while (right + 1 < s.size() && s[right] == s[right + 1])
            right++;
        i = right + 1;
        while (left >= 0 && right < s.size() && s[left] == s[right]) 
        {
            left--; 
            right++; 
        }
        if (len < right - left - 1)
        {
            len = right - left - 1;
            leftRes = left;
            maxRes = len;
        }
    }

    return s.substr(leftRes + 1, maxRes);
    }
};

然後檢測結果顯示如下:

技術分享圖片

超過了100%並且顯示執行速度為0ms,厲害了。

之後大致看了看之前排第一的算法,發現是用“#”把字符填充為原來的2n+1再從中心字符進行演算,完全沒這位哥的巧妙,這裏就不提了。

題目:最長回文子串(C++)