131. Palindrome Partitioning

来源:互联网 发布:vb for mac 编辑:程序博客网 时间:2024/04/29 21:27

题目:回文分区

Given a string s, partition s such that every substring of the partition is a palindrome.

Return all possible palindrome partitioning of s.

For example, given s = "aab",
Return

[  ["aa","b"],  ["a","a","b"]]

题意:

给定一个字符串s,分隔s字符串使得每个部分的子串都是回文的。返回s字符串的所有可能的回文分区。


转载:leetcode题解

思路一:

在每一步都可以判断中间结果是否为合法结果,用回溯法。一个长度为n 的字符串,有n - 1 个地方可以砍断,每个地方可断可不断,因此复杂度为O(2^(n-1))。每次最先判断较长的部分,依次回溯。

代码:C++版:12ms

// 时间复杂度O(2^n),空间复杂度O(n)class Solution {public:    vector<vector<string>> partition(string s) {        vector<vector<string>> res;        vector<string> path; //存储一个partition方案        dfs(s, path, res, 0, 1);        return res;    }    // s[0, prev-1] 之间已经处理,保证是回文串    // prev 表示s[prev-1] 与s[prev] 之间的空隙位置,start 同理    void dfs(string &s, vector<string> &path, vector<vector<string>> &res, int prev, int start) {        if (start == s.size()) { //最后一个隔板            if (isPalindrome(s, prev, start-1)) { //必须使用                path.push_back(s.substr(prev, start-prev));                res.push_back(path);                path.pop_back();            }            return;        }        // 不断开        dfs(s, path, res, prev, start+1);        // 如果[prev, start-1] 是回文,则可以断开,也可以不断开(上一行已经做了)        if (isPalindrome(s, prev, start-1)) {            //断开            path.push_back(s.substr(prev, start-prev));            dfs(s, path, res, start, start+1);            path.pop_back();        }    }    bool isPalindrome(const string &s, int start, int end) {        while (start < end && s[start] == s[end]) {            ++start;            --end;        }        return start >= end;    }};

思路二:

另一种切割写法,代码更为简洁。从短的部分进行判断和切割,先判断每个字符是否是回文,接着判断两个、三个。。连续的字符串是否是回文的。

代码:C++版:12ms

// 时间复杂度O(2^n),空间复杂度O(n)class Solution {public:    vector<vector<string>> partition(string s) {        vector<vector<string>> res;        vector<string> path; //存储一个partition方案        dfs(s, path, res, 0);        return res;    }    // 搜索必须以s[start] 开头的partition 方案    void dfs(string &s, vector<string> &path, vector<vector<string>> &res, int start) {        if (start == s.size()) {            res.push_back(path);            return;        }        for (int i=start; i<s.size(); i++) {            if (isPalindrome(s, start, i)) { // 从i 位置砍一刀                path.push_back(s.substr(start, i-start+1));                dfs(s, path, res, i+1); // 继续往下砍                path.pop_back(); // 撤销上上行            }        }    }    bool isPalindrome(const string &s, int start, int end) {        while (start < end && s[start] == s[end]) {            ++start;            --end;        }        return start >= end;    }};

思路三:

采用动态规划DP实现。利用一个二维数组p[n][n]存储字符串s的下标i到j之间的子串是否是回文串。在对p[n][n]数组进行赋值时,只需要比较一个回文串两端的字符是否相等,如果相等,则i-1,j+1,之后基于p[n][n]二维数组值字符串进行分割处理,保存等操作。

代码:C++版:80ms

class Solution {public:    vector<vector<string>> partition(string s) {        const int n = s.size();        bool p[n][n]; //用来存储字符串s的子串i到j之间是否是回文串        fill_n(&p[0][0], n * n, false); //将p[n][n]二维数组初始化都为false                for (int i = n - 1; i >= 0; --i) //将只有一个元素或者中间子串为回文串的部分置为回文标识true            for (int j = i; j < n; ++j)                p[i][j] = s[i] == s[j] && ((j - i < 2) || p[i + 1][j - 1]);                        vector<vector<string>> sub_palins[n]; // sub palindromes of s[0,i]        for (int i = n - 1; i >= 0; --i) {            for (int j = i; j < n; ++j)                if (p[i][j]) { //根据二维数组p[n][n]查询i到j之间的子串是否是回文串                    const string palindrome = s.substr(i, j - i + 1); //将回文串截取出来                    if (j + 1 < n) {                         for (auto v : sub_palins[j + 1]) {                            v.insert(v.begin(), palindrome);                            sub_palins[i].push_back(v);                        }                    } else {                        sub_palins[i].push_back(vector<string> { palindrome });                    }                }            }        return sub_palins[0];    }};

0 0
原创粉丝点击