• LeetCode:Palindrome Partitioning


    LeetCode:Palindrome Partitioning

    题目如下:(把一个字符串划分成几个回文子串,枚举所有可能的划分)

    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"] ]

    分析:首先对字符串的所有子串判断是否是回文,设f[i][j] = true表示以i为起点,长度为j的子串是回文,等于false表示不是回文,那么求f[i][j]的动态规划方程如下:

    • 当j = 1,f[i][j] = true;

    • 当j = 2,f[i][j] = (s[i]==s[i+1]),其中s是输入字符串

    • 当j > 2, f[i][j] = f[i+1][j-2] && (s[i] == s[i+j-1])(即判断s[m..n]是否是回文时:只要s[m+1...n-1]是回文并且s[m] = s[n],那么它就是回文,否则不是回文)

    这一题也可以不用动态规划来求f,可以用普通的判断回文的方式判断每个子串是否为回文。                                                                                                               本文地址

    求得f后,根据 f 可以构建一棵树,可以通过DFS来枚举所有的分割方式,代码如下:

    复制代码
     1 class Solution {
     2 public:
     3     vector<vector<string>> partition(string s) {
     4         // IMPORTANT: Please reset any member data you declared, as
     5         // the same Solution instance will be reused for each test case.
     6         vector< vector<string> >res;
     7         int len = s.length();
     8         if(len == 0)return res;
     9         //f[i][j] = true表示以i为起点,长度为j的子串是回文
    10         bool **f = new bool*[len];
    11         for(int i = 0 ; i < len; i++)
    12         {
    13             f[i] = new bool[len+1];
    14             for(int j = 0; j < len+1; j++)
    15                 f[i][j] = 0;
    16             f[i][1] = true;
    17         }
    18         for(int k = 2; k <= len; k++)
    19         {
    20             for(int i = 0; i <= len-k; i++)
    21             {
    22                 if(k == 2)f[i][2] = (s[i] == s[i+1]);
    23                 else f[i][k] = f[i+1][k-2] && (s[i] == s[i+k-1]);
    24             }
    25         }
    26         vector<string> tmp;
    27         DFSRecur(s, f, 0, res, tmp);
    28         for(int i = 0 ; i < len; i++)
    29             delete [](f[i]);
    30         delete []f;
    31         return res;
    32     }
    33     
    34     void DFSRecur(const string &s, bool **f, int i, 
    35             vector< vector<string> > &res, vector<string> &tmp)
    36     {//i为遍历的起点
    37         int len = s.length();
    38         if(i >= len){res.push_back(tmp); return;}
    39         for(int k = 1; k <= len - i; k++)
    40             if(f[i][k] == true)
    41             {
    42                 tmp.push_back(s.substr(i, k));
    43                 DFSRecur(s, f, i+k, res, tmp);
    44                 tmp.pop_back();
    45             }
    46                 
    47     }
    48 };
    复制代码

    LeetCdoe:Palindrome Partitioning II

    题目如下:(在上一题的基础上,找出最小划分次数)

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

    Return the minimum cuts needed for a palindrome partitioning of s.

    For example, given s = "aab",
    Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.                                                                                                          本文地址

    算法1:在上一题的基础上,我们很容易想到的是在DFS时,求得树的最小深度即可(遍历时可以根据当前求得的深度进行剪枝),但是可能是递归层数太多,大数据时运行超时,也贴上代码:

     View Code

    算法2:设f[i][j]是i为起点,长度为j的子串的最小分割次数,f[i][j] = 0时,该子串是回文,f的动态规划方程是:

    f[i][j] = min{f[i][k] + f[i+k][j-k] +1} ,其中 1<= k <j

    这里f充当了两个角色,一是记录子串是否是回文,二是记录子串的最小分割次数,可以结合上一题的动态规划方程,算法复杂度是O(n^3), 还是大数据超时,代码如下:

     View Code

    算法3:同上一题,用f来记录子串是否是回文,另外优化最小分割次数的动态规划方程如下,mins[i] 表示子串s[0...i]的最小分割次数:

    • 如果s[0...i]是回文,mins[i] = 0
    • 如果s[0...i]不是回文,mins[i] = min{mins[k] +1 (s[k+1...i]是回文)  或  mins[k] + i-k  (s[k+1...i]不是回文)} ,其中0<= k < i

    代码如下,大数据顺利通过,结果Accept:                                                                                                                                 本文地址

    复制代码
     1 class Solution {
     2 public:
     3     int minCut(string s) {
     4         // IMPORTANT: Please reset any member data you declared, as
     5         // the same Solution instance will be reused for each test case.
     6         int len = s.length();
     7         if(len <= 1)return 0;
     8         //f[i][j] = true表示以i为起点,长度为j的子串是回文
     9         bool **f = new bool*[len];
    10         for(int i = 0 ; i < len; i++)
    11         {
    12             f[i] = new bool[len+1];
    13             for(int j = 0; j < len+1; j++)
    14                 f[i][j] = false;
    15             f[i][1] = true;
    16         }
    17         int mins[len];//mins[i]表示s[0...i]的最小分割次数
    18         mins[0] = 0;
    19         for(int k = 2; k <= len; k++)
    20         {
    21             for(int i = 0; i <= len-k; i++)
    22             {
    23                 if(k == 2)f[i][2] = (s[i] == s[i+1]);
    24                 else f[i][k] = f[i+1][k-2] && (s[i] == s[i+k-1]);
    25             }
    26             if(f[0][k] == true){mins[k-1] = 0; continue;}
    27             mins[k-1] = len - 1;
    28             for(int i = 0; i < k-1; i++)
    29             {
    30                 int tmp;
    31                 if(f[i+1][k-i-1] == true)tmp = mins[i]+1;
    32                 else tmp = mins[i]+k-i-1;
    33                 if(mins[k-1] > tmp)mins[k-1] = tmp;
    34             }
    35         }
    36         for(int i = 0 ; i < len; i++)
    37             delete [](f[i]);
    38         delete []f;
    39         return mins[len-1];
    40     }
    41 
    42 };
    复制代码

     【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3421283.html

     
     
  • 相关阅读:
    c/c++中两颗璀璨的明珠
    deepin软件中心打不开
    shell之rm -rf的别名设置
    历史命令脚本
    mysql之7xtrabackup
    python之3内置容器
    python之第一个例子hello world
    python之安装
    shell脚本练习(autocert)
    【转】nginx之逻辑运算
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3422290.html
Copyright © 2020-2023  润新知