hiho一下第一周 Hihocoder #1032 : 最长回文子串
#1032 : 最長回文子串
時間限制:1000ms 單點時限:1000ms 內存限制:64MB描述
???小Hi和小Ho是一對好朋友,出生在信息化社會的他們對編程產生了莫大的興趣,他們約定好互相幫助,在編程的學習道路上一同前進。
???這一天,他們遇到了一連串的字符串,于是小Hi就向小Ho提出了那個經典的問題:“小Ho,你能不能分別在這些字符串中找到它們每一個的最長回文子串呢?”
???小Ho奇怪的問道:“什么叫做最長回文子串呢?”
???小Hi回答道:“一個字符串中連續的一段就是這個字符串的子串,而回文串指的是12421這種從前往后讀和從后往前讀一模一樣的字符串,所以最長回文子串的意思就是這個字符串中最長的身為回文串的子串啦~”
???小Ho道:“原來如此!那么我該怎么得到這些字符串呢?我又應該怎么告訴你我所計算出的最長回文子串呢?
???小Hi笑著說道:“這個很容易啦,你只需要寫一個程序,先從標準輸入讀取一個整數N(N<=30),代表我給你的字符串的個數,然后接下來的就是我要給你的那N個字符串(字符串長度<=10^6)啦。而你要告訴我你的答案的話,只要將你計算出的最長回文子串的長度按照我給你的順序依次輸出到標準輸出就可以了!你看這就是一個例子。”
良久,小Ho仍然沒有頭緒,于是只能向小Hi求助。
小Hi清了清嗓子,緩緩說道:“讓我從簡單的說起吧,我給你一個字符串,你能不能告訴我它是不是一個回文串呢?”
小Ho回答道:“這個我當然可以啦!只要將這個字符串反過來,然后比較和原來的字符串是不是一樣的不就行了?”
小Hi追問道:“也就是說你想要新建一個字符串咯?”
小Ho道:“那是當然,不然怎么比較呢?”
小Hi笑道:“但是你有沒有注意到你在比較原來的字符串A和新字符串B的時候,A的第一個字符就是B的最后一個字符,而A的最后一個字符就是B的第一個字符,那么這樣就比較了兩次是不是浪費了效率呢?”
小Ho恍然道:“似乎是這樣的!我知道了,我也不需要新建一個字符串了,我只需要比較A的第一個字符和最后一個字符是否相同,第二個字符和倒數第二個字符是否相同,以此類推,這樣就只要比較字符串長度的一半次數就行了是不是?”
小Hi回答道:“沒錯!那你對于一個字符串,一一枚舉它的子串,然后判斷這個子串是不是回文子串,如果是的話就更新當前保存的最長的那一個,是不是就可以了?”
小Ho開心道:“是的!這個問題是不是就這么解決了?”
小Hi嘆息道:“NONONO!你這最多也就拿個60分吧。”
小Ho遺憾的說道:“才及格啊,那我要怎么多拿點分呢?”
小Hi道:“不急不急,待我慢慢道來,你有沒有想過之前的解法有沒有什么問題?”
小Ho問道:“有什么問題?”
小Hi道:“你想想,如果一個字符串的[3, 7]這一段已經不是回文子串了,[2, 8]這一段還有可能是回文子串么?”
小Ho驚道:“好像不可能,那我之前不是有很多的計算都白費了,有沒有什么辦法來解決這個問題呢?我得好好想想!”言罷,小Ho沉思了起來。
良久,代表著成功的微笑出現來的小Ho的嘴邊:“我知道了!我在枚舉子串的時候換一種方式來進行枚舉,不是枚舉它的起止位置而是嘗試枚舉子串的中心位置,然后再從小到大依次枚舉這個子串的長度,一旦發現已經不是一個回文串了就繼續嘗試下一個中心位置,這樣,似乎就能夠避免掉很多問題呢!”
小Hi贊許的點了點頭,說道:“沒錯,這樣的確會在一些情況下降低用于計算的時間呢,但是一個全是a的字符串,你這樣的枚舉方法似乎也沒有多大用處呢?不過這樣你也能拿個80分了哦!”
小Ho點了點頭,說道:“沒錯,在最壞情況下,這種方法并沒有比之前的方法好到哪里去,但是我的直覺告訴我肯定有更加高效的方法來進行計算呢,讓我再好好想想吧!?!?/p>
小Ho這一想就是三天,小Hi也是看不下去了,決定來開導開導小Ho:“小Ho,你有沒有想過,在之前的計算中,計算出以每一個位置為中心的最長回文子串的長度有沒有什么用呢?”
小Ho答道:“我想想,如果以第5個字符為中心的最長回文子串的長度是5的話,這就告訴了我[3, 7]這一段是一個回文子串,所以呢?”
小Hi繼續提示道:“假設這時候你想要計算以第6個字符為中心的最長回文子串的長度,你有沒有什么已知的信息了?”
小Ho邊想邊說道:“唔,首先第6個字符和第4個字符是一樣的,第7個字符和第3個字符是一樣的,而第5個字符本身就肯定和第5個字符一樣,那么如果[3, 5]這一段是回文子串的話,那么[5, 7]這一段肯定也是回文子串。也就是說,如果令f[i] 表示以第i個字符為中心的最長回文子串的長度,我們就會有f[i] >= f[i–2]?”
“不對,還要考慮到f[i – 1]的值,如果f[i – 1]太小就沒有意義了,應該是f(i)≥min?{f(i-2), f(i-1)-2}?!毙o接著補充道。
“沒錯,但是還有一個問題,如果此時我告訴你f(5) = 1,但是f(4) = 7, f(2) = 3呢?”小Hi追問道。
小Ho想了想,回答道:“理論上來說,我可以通過這些信息知道f(6)>=3,但是由于f(5)=1所以我只能計算出來f(6)>=-1我知道了,我不應該是通過f(i – 1)來輔助計算,而是通過使得右邊界(j + f(j) / 2)最大的那個j來輔助計算才是,所以公式將變成 f(i) ≥ min{f(2*j-i) , f(j) -2*(i-j)}這種形式了!”
小Hi繼續問道:“那知道了這個公式之后,你打算怎么做呢?”
小Ho想也沒想便道:“這簡單,我只要在之前枚舉中心位置那種方法的基礎上,統計使得回文串右邊界(j + f(j) / 2)最大的那個j,然后再計算每一個i的時候,都可以通過f(i)≥min?{f(2*j-i), f(j)-2*(i-j)}這個公式來知道f(i)的一個最小值,這樣即使是在我們所提到的那種最壞情況下,也可以節省掉很多不必要的計算呢~
一晃就是一周過去了,小Hi還是沒有看到小Ho寫的程序,于是決定上門去問問。到了小Ho家,小Hi驚訝的發現小Ho對著電腦屏幕,一臉郁悶的樣子,于是他走上前問道:“小Ho小Ho,你怎么了啊?”
小Ho一點精神也沒有的回答道:“就是上周的那個回文子串的程序啊,我寫的時候發現我們當時考慮的解決方法只能處理長度為奇數的回文子串,長度為偶數的回文子串似乎要進行一點點細微的修改,但是這樣修改過后就不能用我們最后寫出的那個公式來互相幫助進行運算了,要進行很復雜的討論,我就是一直在想有沒有很優美的方法能來解決這個問題?!?/p>
小Hi驚訝道:“你就想這個想了一周么?我猜你一定是繞進了分類討論的這個胡同里走不出來了,為什么不想想有沒有別的解決方法呢?”
小Ho問道:“還有什么解決方法呀?”
小Hi答道:“既然長度為偶數的回文子串不好處理,我們為什么不去掉這些回文子串,只處理長度為奇數的回文子串呢?”
小Ho嘆息道:“但是長度為偶數的回文子串也可以是答案啊!”
“除非……”小Hi插嘴道。
“除非什么?”小H問道。
“你將所有的長度為偶數的回文子串都變成長度為奇數的回文子串啊,你想想之所以是為偶數,那是因為沒有一個中心字符,但是如果我們在原來字符串的基礎上,在任意兩個相鄰的字符間都插入一個特殊字符,是不是無論是原來字符串中長度為奇數的回文子串還是長度為偶數的回文子串,在新的字符串中都有一個長度為奇數的回文子串與之進行對應呢?”
“哦!我了解了,這樣我只需要對新的字符串按照我們之前的算法進行計算,統計出的最長回文子串將那些特殊字符去掉之后,就是原來字符串里的最長回文子串了?!毙?span style="font-family:Calibri,serif">Ho開心的笑道,一連幾天的郁悶也是一掃而空。
“但是要注意哦,我們希望得到的最長是原來字符串里的最長,而不是新字符串里的最長,畢竟特殊字符的個數會因為中心字符是不是特殊字符而有差別的哦。”小Hi提醒道。
“恩恩,這樣我總能拿到滿分了吧?”
“沒錯呢!”
樣例輸入總結
以上是生活随笔為你收集整理的hiho一下第一周 Hihocoder #1032 : 最长回文子串的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: hiho一下第二周 Hihocoder
- 下一篇: hiho一下 第三周 Hiocoder
