【算法题】分割回文串

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

【算法题】分割回文串

盖世阿萌   2020-04-04 我要评论

题目:

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回 s 所有可能的分割方案。

举例:

输入: "aab"
输出:
[
  ["aa","b"],
  ["a","a","b"]
]

解题思路:

再举个稍微长一点的例子吧,比如aabcc,我第一眼看到之后用我那普通人类的头脑开始列方案了:

单独一个字符是回文串:a|abcc

然后分析abcc,单独切一个a是回文:a|bcc,(ab,abc和abcc都不是回文就不考虑这三种切法了(因此对于abcc就a|bcc这一种

再来bcc,单独一个b是回文:b|cc,(bc,bcc也不是回文(因此对于bcc就b|cc这一种

最后cc,单独一个c是回文:c|c,或者两个c也构成了回文:cc|

c|c中,后面这个c,再切它就是c|,所以现在就和cc|一样分到底了,因为“|”后面是空的。

整理一下,【a,b,c,c】和【a,b,cc】是这次的结果,但还远没有结束!

因为是从a后面开始分割的,接下来可以从aa|bcc,aab|cc,aabc|c,aabcc|的角度来切,每次切完固定 | 前面的部分,用同样的切切法分析 | 后面的部分。

到这里似乎有了点什么灵感呢~

每次都从头开始遍历,一个字符两个字符三个字符这样检查,如果是一段回文那就切开,切点后面的部分用同样的方法;

如果切点后是空了就返回一个空list,在返回的不同路线上把前面的切头加在这个list的前面,一直返回到路线的最开始就是结果了。

表达能力有点捉鸡,总之就是先从头到尾切切切,再从尾到头加加加的过程,科学一点的说法就是“分治”。把大字符串切成小字符串,小字符串切到空。

可以用迭代(栈)或者是递归的方法。

贴一个JAVA代码:

class Solution {
    public List<List<String>> partition(String s) {
        boolean[][] dp=new boolean[s.length()][s.length()];
        for(int len=1;len<=s.length();len++){
            for(int i=0;i<=s.length()-len;i++){
                if(len==1)dp[i][i]=true;
                else if(s.charAt(i)==s.charAt(i+len-1)&&(len==2||dp[i+1][i+len-2])){
                    dp[i][i+len-1]=true;
                }
            }
        }
        return solution(s,0,dp);
    }
    public List<List<String>> solution(String s,int start,boolean[][] dp){
        ArrayList<List<String>> list=new ArrayList<>();
        if(start==s.length()){//切到空空如也,就返回一个空list,让前辈们往上加吧
            List<String> li=new ArrayList<>();
            list.add(li);
            return list;
        }
        for(int i=start;i<s.length();i++){//非常认真地一个一个字符找,看能不能切
            if(dp[start][i]){//啊,从start到i是回文!切它!
                String first=s.substring(start,i+1);
                for(List<String> li:solution(s,i+1,dp)){
                    li.add(0,first);//把返回得到的一到多个list前面都分别加上切掉的部分
                    list.add(li);
                }
            }
        }
        return list;
    }
    
}

PS:这里呢,为了方便判断string的一段是不是回文,提前用动态规划法做了一个dp数组,如果这段是回文就记录为true。

1、回文长度 len 是1、2、3、4、...、length。

2、回文的起点 i 是0、1、2、3、...、length-len(后面长度不足len了就肯定不是len长的回文了)。

3、如果长度len为1,那就一个字符了肯定是回文了;

如果长度为2,且起点的字符==终点的字符,起点挨着终点,他俩还相等,那稳了;

如果长度大于2,且起点的字符==终点的字符,如果他们内层是回文那就是回文了,dp[i+1][i+len-2]表示从起点+1到终点-1的字符串是否是回文。

     boolean[][] dp=new boolean[s.length()][s.length()];
        for(int len=1;len<=s.length();len++){
            for(int i=0;i<=s.length()-len;i++){
                if(len==1)dp[i][i]=true;
                else if(s.charAt(i)==s.charAt(i+len-1)&&(len==2||dp[i+1][i+len-2])){
                    dp[i][i+len-1]=true;
                }
            }
        }

PPS:去LeetCode写一哈吧,一定要动手才知道会不会呀!

https://leetcode-cn.com/problems/palindrome-partitioning/

 

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们