38 分割回文串(Palindrome Partitioning)

文章目录

    • 1 题目
    • 2 解决方案
      • 2.1 思路
      • 2.2 时间复杂度
      • 2.3 空间复杂度
    • 3 源码

1 题目

题目:分割回文串(Palindrome Partitioning)
描述:给定字符串 s,需要将它分割成一些子串,使得每个子串都是回文串。返回所有可能的分割方案。

  1. 不同的方案之间的顺序可以是任意的。
  2. 每种分割方案中的每个子串都必须是 s 中连续的一段。

lintcode题号——136,难度——medium

样例1:

输入: "a"
输出: [["a"]]
解释: 字符串里只有一个字符, 也就只有一种分割方式 (就是它本身)

样例2:

输入: "aab"
输出: [["aa", "b"], ["a", "a", "b"]]
解释: 有两种分割的方式.
    1. 将 "aab" 分割成 "aa" 和 "b", 它们都是回文的.
    2. 将 "aab" 分割成 "a", "a" 和 "b", 它们全都是回文的.

2 解决方案

2.1 思路

  要将整个串分割成回文串,必须将所有分割的可能情况都遍历一遍并逐一验证是否回文,对于这样遍历所有的操作,可以考虑使用深度优先搜索(Depth First Search)来找到所有分割子串。

DFS常用于需要遍历出所有解的场景中,例如求所有子集、得到所有组合、全排列等经典问题。

2.2 时间复杂度

  深度优先搜索的时间复杂度的计算方式是逻辑图上的节点数(即所有元素的组合数,n个元素,每个元素都有取或不取两种可能,所以是2的n次方)与处理每个节点的耗时的乘积,也可以看作答案个数与构造每个答案花费的时间的乘积,该题的算法的时间复杂度为O(2^n * n)。

2.3 空间复杂度

  图上的宽度优先搜索,使用了vector数据结构保存节点,算法的空间复杂度为O(n)。

3 源码

细节:

  1. 该题使用常规方式进行DFS会需要更多临时变量来保存子串的相关信息(起点、长度等),这里使用一个技巧,将递归用的主串随着递归的深入进行不断缩减,这样可以简化代码逻辑,代码与标准DFS尽量一致。

C++版本:

/*
* @param s: A string
* @return: A list of lists of string
*/
vector> partition(string &s) {
    // write your code here
    vector> results;
    if (s.empty())
    {
        return results;
    }
    
    vector path;
    dfs(s, path, results);
    
    return results;
}

void dfs(string s, vector path, vector> & results)
{
    if (s.empty())
    {
        results.push_back(path);
        return;
    }
    
    for (int i = 0; i < s.size(); i++)
    {
        if (isPalindrome(s.substr(0, i + 1)))
        {
            path.push_back(s.substr(0, i + 1));
            dfs(s.substr(i + 1), path, results);
            path.pop_back();
        }
    }
}

bool isPalindrome(const string & s)
{
    int left = 0;
    int right = s.size() - 1;
    while (left < right)
    {
        if (s.at(left) != s.at(right))
        {
            return false;
        }
        left++;
        right--;
    }
    
    return true;
}

你可能感兴趣的:(#,深度优先搜索,算法,算法,深度优先)