1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        ?LeetCode刷題實戰(zhàn)214:最短回文串

        共 8094字,需瀏覽 17分鐘

         ·

        2021-03-19 14:01

        算法的重要性,我就不多說了吧,想去大廠,就必須要經(jīng)過基礎(chǔ)知識和業(yè)務(wù)邏輯面試+算法面試。所以,為了提高大家的算法能力,這個公眾號后續(xù)每天帶大家做一道算法題,題目就從LeetCode上面選 !

        今天和大家聊的問題叫做 最短回文串,我們先來看題面:
        https://leetcode-cn.com/problems/shortest-palindrome/

        You are given a string s. You can convert s to a palindrome by adding characters in front of it.


        Return the shortest palindrome you can find by performing this transformation.

        題意


        給定一個字符串 s,你可以通過在字符串前面添加字符將其轉(zhuǎn)換為回文串。找到并返回可以用這種方式轉(zhuǎn)換的最短回文串。

        示例


        示例 1

        輸入:s = "aacecaaa"
        輸出:"aaacecaaa"

        示例 2

        輸入:s = "abcd"
        輸出:"dcbabcd"
         
        提示:

        0 <= s.length <= 5 * 104
        s 僅由小寫英文字母組成



        解題

        https://blog.csdn.net/qq_41231926/article/details/86747126

        思路一:暴力破解法

        要找到滿足題目要求的最短回文串,本質(zhì)是要找到最長的回文子串,該子串的左端點與字符串s的左端點重合。
        時間復(fù)雜度是O(n ^ 2),其中n為字符串s的長度??臻g復(fù)雜度是O(n)。
        JAVA代碼:
        class Solution {
            public String shortestPalindrome(String s) {
                int index = -1;
                for(int i = s.length() - 1; i >= 0; i--){
                    if(isPalindrome(s.substring(0, i + 1))){
                        index = i;
                        break;
                    }
                }
                String result = reverse(s.substring(index + 1));
                return result + s;
            }
            private String reverse(String s){
                StringBuilder stringBuilder = new StringBuilder(s);
                return stringBuilder.reverse().toString();
            }
            private boolean isPalindrome(String s){
                for(int i = 0; i < s.length() / 2; i++){
                    if(s.charAt(i) != s.charAt(s.length() - 1 - i)){
                        return false;
                    }
                }
                return true;
            }
        }

        思路二:遞歸解法

        左指針i初始化為0,右指針j從n - 1遞減到0,其中n為字符串s的長度,一旦遇上i指向的字符與j指向的字符相等時,令i指針加1。

        遞歸出口:

        如果i指針最后的值等于n,說明字符串s本身就是回文串,直接返回s即可。

        遞歸過程:

        首先明確一點:我們所要尋找的最長回文子串,該子串的左端點與字符串s的左端點重合,一定在[0, i)范圍內(nèi)。

        考慮兩種極端情況,第一種情況:字符串s本身就是回文串,顯然滿足條件。第二種情況:在遍歷過程中,不存在i指向的字符與j指向的字符相等的情況,除了i和j相等時,這種情況我們得到的i是1。顯然也滿足條件。

        考慮一般性情況:假設(shè)我們所要尋找的最長回文子串不在[0, i)范圍內(nèi),即存在回文串其在[0, k)范圍內(nèi),其中k > i。那么顯然,在我們遍歷的過程中,即使j在[k, n - 1]范圍時不存在i指向的字符與j指向的字符相等的情況,最終i的值也會到達(dá)k,即i >= k,這顯然矛盾了,因此該結(jié)論成立。

        由上述結(jié)論,我們得出:[i, n - 1]范圍內(nèi)的子串一定不是我們所要尋找的最長回文子串的一部分。

        這樣,我們就可以遞歸地反轉(zhuǎn)[0, i)范圍內(nèi)的子串來拼接出結(jié)果。

        時間復(fù)雜度是O(n ^ 2),其中n為字符串s的長度??臻g復(fù)雜度是O(n)。

        JAVA代碼:

        class Solution {
            public String shortestPalindrome(String s) {
                int i = 0;
                for(int j = s.length() - 1; j >= 0; j--){
                    if(s.charAt(j) == s.charAt(i)){
                        i++;
                    }
                }
                if(i == s.length()){
                    return s;
                }
                return reverse(s.substring(i)) + shortestPalindrome(s.substring(0, i)) + s.substring(i);
            }
            private String reverse(String s){
                StringBuilder stringBuilder = new StringBuilder(s);
                return stringBuilder.reverse().toString();
            }
        }

        思路三:KMP算法

        將原字符串s和其逆序字符串用“#”拼接在一起,利用KMP算法中next數(shù)組的求法求得拼接出的新字符串的最長相同前后綴,就是原字符串s中最長的回文子串,該子串的左端點與字符串s的左端點重合。

        這個問題是一個動態(tài)規(guī)劃問題:求取字符串s中的最長相同前后綴(不能是其本身)

        狀態(tài)定義:

        f(x) -------- 字符串s中[0, x]范圍內(nèi)的最長相同前后綴(不能是其本身)的長度

        狀態(tài)轉(zhuǎn)移:

        首先是初始化,f(0)顯然是0,因為[0, 0]范圍內(nèi)的字符串長度為1,其最長相同前后綴根本不存在。

        對于i在[1, n - 1](其中n為字符串s的長度)范圍內(nèi)的值:

        (1)令temp記錄f(x - 1)的值,如果temp大于0且s中temp位置的字符和第i個字符不相同,那么我們就需要重設(shè)temp的值為f(temp - 1)。

        (2)如果s中第i個字符與第temp個字符相同,令temp自增1。

        (3)f(i) = temp。

        上述狀態(tài)轉(zhuǎn)移過程可能很難理解,以一個例子——“ABABCABAA”來說明,其子串如下:

        A -------------------------------------------------- 0

        AB ------------------------------------------------ 0

        ABA ---------------------------------------------- 1

        ABAB -------------------------------------------- 2

        ABABC ------------------------------------------ 0

        ABABCA ---------------------------------------- 1

        ABABCAB -------------------------------------- 2

        ABABCABA ------------------------------------ 3

        ABABCABAA ---------------------------------- 1

        對由ABAB求得ABABC這個過程進行分析:

        C和A不相等,因此結(jié)果不可能是3,如果是ABABA,則結(jié)果是3。ABAB的結(jié)果是2,因此我們知道AB和AB相同,但是第一個AB之后跟著的是A,依然和C不相同。我們繼續(xù)看AB,AB的結(jié)果是0,因此我們知道AB中A和B不相同,而C和A不相同,因此結(jié)果是0。

        對由ABABCABA求得ABABCABAA這個過程進行分析:

        A和B不相等,因此結(jié)果不可能是4,如果是ABABCABAB,則結(jié)果是4。ABABCABA的結(jié)果是3,因此我們知道ABA和ABA相同,但是第一個ABA之后跟著的是B,依然和A不相同。我們繼續(xù)看ABA,ABA的結(jié)果是1,但是第一個A之后跟著的是B,依然和A不相同。我們繼續(xù)看A,結(jié)果是0,結(jié)束while循環(huán)。這個A和A相同,因此其值加1變成1。

        時間復(fù)雜度和空間復(fù)雜度均是O(n),其中n為字符串s的長度。

        JAVA代碼:

        class Solution {
            public String shortestPalindrome(String s) {
                String rev = reverse(s);
                String temp = s + "#" + rev;
                int[] next = getNext(temp);
                return rev.substring(0, rev.length() - next[temp.length() - 1]) + s;
            }
            private String reverse(String s){
                StringBuilder stringBuilder = new StringBuilder(s);
                return stringBuilder.reverse().toString();
            }
            private int[] getNext(String s){
                int[] result = new int[s.length()];
                result[0] = 0;
                for(int i = 1; i < result.length; i++){
                    int temp = result[i - 1];
                    while(temp > 0 && s.charAt(i) != s.charAt(temp)){
                        temp = result[temp - 1];
                    }
                    if(s.charAt(i) == s.charAt(temp)){
                        temp++;
                    }
                    result[i] = temp;
                }
                return result;
            }
        }

        好了,今天的文章就到這里,如果覺得有所收獲,請順手點個在看或者轉(zhuǎn)發(fā)吧,你們的支持是我最大的動力 。

        上期推文:

        LeetCode1-200題匯總,希望對你有點幫助!

        LeetCode刷題實戰(zhàn)201:數(shù)字范圍按位與

        LeetCode刷題實戰(zhàn)202:快樂數(shù)

        LeetCode刷題實戰(zhàn)203:移除鏈表元素

        LeetCode刷題實戰(zhàn)204:計數(shù)質(zhì)數(shù)

        LeetCode刷題實戰(zhàn)205:同構(gòu)字符串

        LeetCode刷題實戰(zhàn)206:反轉(zhuǎn)鏈表

        LeetCode刷題實戰(zhàn)207:課程表

        LeetCode刷題實戰(zhàn)208:實現(xiàn) Trie (前綴樹)

        LeetCode刷題實戰(zhàn)209:長度最小的子數(shù)組

        LeetCode刷題實戰(zhàn)210:課程表 II

        LeetCode刷題實戰(zhàn)211:添加與搜索單詞

        LeetCode刷題實戰(zhàn)212:單詞搜索 II

        LeetCode刷題實戰(zhàn)213:打家劫舍 II


        瀏覽 36
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點贊
        評論
        收藏
        分享

        手機掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            少妇性受XXXX黑人XYX性爽 | 免费啪啪网 | 日本三级中国三级99 | 大香蕉五月婷婷 | 一级黄片操逼视频 | 欧美女人操逼视频 | 丁香花婷婷 | 大香蕉伊人在线看 | 免费的成人A片无码同人 | 国产精品1区 |