1. 程式人生 > 其它 >詳解將Python程式(.py)轉換為Windows可執行檔案(.exe)

詳解將Python程式(.py)轉換為Windows可執行檔案(.exe)

Able was I ere I saw Elba. ----Napoléon Bonaparte(拿破崙)

一、迴文串&迴文子串

 這個很好理解。

  如果一個字串正著讀和反著讀是一樣的,那它就是迴文串。 eg. abba ;

  如果一個字串 S 的子串 SS 為迴文串,那麼 SS 即為 S 的迴文子串;若 SSS 為 S 的迴文子串中最長的一個,那麼我們稱 SSS 為 S 的最長迴文子串

二、Manacher演算法

  如何找到一個字串的最長迴文子串呢?

  我們很容易想到一個 O(n2) 的方法,即:從每個字元開始向兩邊爆搜。但顯然,這個方法效率太低下了。

  如何快速求出答案,這就是 Manacher演算法的事了。

  Ⅰ. 奇迴文&偶迴文

    字面意思,不再贅述。

    如果同時存在奇迴文和偶迴文,那麼處理起來會比較的繁瑣,下面就是Manacher 一個很巧妙的方法了:在字串收尾,即各字元間插入一個特殊的字元(指沒有出現過的字元),例如:

aba  ----> #a#b#a#
abba ----> #a#b#b#a#

    這樣,所有的迴文串就都成奇迴文了。

inline int Pre()
{
    S[0]='@',S[1]='#';
    int j(1);
    for(register int i=0,len=IP.size();i<len;++i) S[++j]=IP[i],S[++j]='
#'; S[++j]='\0';return j; }
預處理

  Ⅱ. 最長迴文半徑

    令一個迴文串中最左或最右位置的字元與其對稱軸的距離稱為 " 迴文半徑 ",令 R [ i ] 表示字元 i 的最長迴文半徑。

i 0 1 2 3 4 5 6 7 8 9 10
S @ a # b # b # a # b $
R[i] 邊界 1 1 2 4 2 1 4 1 2 邊界

    顯然,R [ i ] - 1 即為以 i 為中心的最長迴文子串的長度。

    那麼,我們要求的最長迴文子串,就成了 max { R [ i ] - 1 }

    如何快速求出 R [ ] ???

  Ⅲ.Manacher

    從左往右依次討論。

    設 Max 為已討論的子串中能達到的右端最大位置,P 為提供當前 Max 的字元位置。如下表:

i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Max的對稱點 P Max

    

    接下來討論的位置 i 可以分為兩種情況:小於等於 Max ,大於 Max:

      1. 小於等於 Max :

i 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Max的對稱點 j(i的對稱點) P i Max

      由於 i 和 j 對稱 ,所以求出 i 的對稱點 j ,簡直是 "輕易而舉" 。

      

      不難發現現在有可以分為兩種情況討論

         ( 1 ) .以 j 為對稱軸的迴文串比較短:那麼可以直接令 R [ i ] = R [ j ] ;

         ( 2 ) .以 j 為對稱軸的迴文串比較長:此時,我們只能確定不超過 Max 的部分的情況,對於 Max 以外的,我們需要以 i 為中心開始往兩側拓展,直到兩側不同,同時更新 p 和 Max。

       

       2. 大於 Max : 這種情況很好處理,直接拓展就可以了(當然,要同時更新 p 和 Max)

  Ⅳ. 程式碼

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include<bits/stdc++.h>
using namespace std;
char S[50000005];
int m,R[50000005];
string IP;
inline int Pre()
{
    S[0]='@',S[1]='#';
    int j(1);
    for(register int i=0,len=IP.size();i<len;++i) S[++j]=IP[i],S[++j]='#';
    S[++j]='\0';return j;
}
inline int Manacher()
{
    m=Pre();
    int RET(-1),x(0),Max(0);
    for(register int i=1;i<m;++i)
    {
        if(i<Max) R[i]=min(R[2*x-i],Max-i+1);
        else R[i]=1;
        while(S[i-R[i]]==S[i+R[i]]) ++R[i];
        if(Max<i+R[i]-1) x=i,Max=i+R[i]-1;
        RET=max(RET,R[i]-1);
    }
    return RET;
}
int main()
{
    ios::sync_with_stdio(false);
    cin>>IP,cout<<Manacher();
    return 0;
}
Manacher

  Ⅴ. 時間複雜度

    由於Max是不斷向右拓展的,最多拓展 n 次,不難得出 馬拉車 的時間複雜度是線性的,即 O( n )。