分割回文串

一、需求

  • 给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是 回文串 ,返回 s 所有可能的分割方案;

示例 1:

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

提示:

  • 1 <= s.length <= 16
  • s 仅由小写英文字母组成

二、DFS

2.1  思路分析

  1. 题目给定一个字符串,然后设计一个算法,将这个字符串分割成回文子串,将所有的分割方案存储的集合中并返回;
  2. 现在要分析,如何根据给定的字符串得到所有可能的分割方案呢?如下图所示:

         

     3.根据上图可以发现,对于给定字符串,当字符串为空串时,将各个截取的字串合在一起就是一种分割方案,这样上图有两种方案:["a","a","b"],["aa","b"];

     4.根据该图分析解决问题的思路:①使用栈来记录从根串到空串的路径,这样做的原因是方便回溯,最后添加的最先出去;②遍历字符串,假设当前索引为 i ,判断以索引 i 为结尾的子串是否为回文串,如果不是则遍历下一个字符,否则加当前回文串入栈,然后递归的执行起始索引 i 以后的字符串内容,执行结束后回溯;

2.2  代码实现

class Solution {
    public List<List<String>> partition(String s) {
        List<List<String>> res = new ArrayList<>();
        if(s == null || s.length() == 0) {
            return res;
        }
        Deque<String> path = new ArrayDeque<>();
        char[] ch = s.toCharArray();
        dfs(ch, path, res, 0);
        return res;
    }
    /**
     *该方法将所有分割方案添加到集合中
     *@param ch      给定字符串的数组形式
     *@param path    存储分割方案中的回文串
     *@param res     存储所有的分割方案
     *@param index   遍历字符串的索引
     */
    public void dfs(char[] ch, Deque<String> path, List<List<String>> res, int index) {
        if(index == ch.length) {
            res.add(new ArrayList(path));
            return;
        }
        for(int i = index; i < ch.length; i++) {
            if(!palindrome(ch, index, i)) {
                continue;
            }
            path.addLast(new String(ch, index, i-index+1));
            dfs(ch, path, res, i + 1);
            path.removeLast();
        }
    }
    /**
     *该方法用来判断是否为回文串
     *@param ch     给定字符串的数组形式
     *@param left   字符串的起始索引下标
     *@param right  字符串的结束索引下标
     */
    public boolean palindrome(char[] ch, int left, int right) {
        while(left < right) {
            if(ch[left] != ch[right]) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
}

2.3  复杂度分析

  • 时间复杂度为O(N*2^N),其中N为字符串字符的个数,最坏情况下,字符串中的字符全部相同时,那么字符串的划分方案数就有2^{N-1}中,每一种划分都需要O(N)的时间来存储结果;
  • 空间复杂度为O(N),其中返回值不作为空间消耗,若考虑返回值,则空间复杂度为O(N*2^N)

三、学习地址

作者:liweiwei1419

链接:https://leetcode-cn.com/problems/palindrome-partitioning/solution/hui-su-you-hua-jia-liao-dong-tai-gui-hua-by-liweiw/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
动态规划分割回文串是一种常用的解决方案。在动态规划中,我们可以使用不同的状态定义和状态转移方程来解决这个问题。 一种常见的状态定义是使用一维数组dp[i],其中dp[i]表示字符串s的前i个字符形成回文子串的最少分割次数。这种定义可以通过判断s[j:i]是否为回文来进行状态转移,其中1 <= j <= i。具体的状态转移方程可以如下表示: - 当s[0:i]本身就是一个回文串时,不需要进行分割,即dp[i] = 0。 - 否则,我们可以遍历所有可能的分割点j,如果s[j+1:i]是回文串,那么我们可以将问题分割为两部分,即dp[i] = min(dp[i], dp[j] + 1)。 另一种状态定义是使用二维数组dp[i][j],其中dp[i][j]表示字符串s的前i个字符分割为j个子串的修改的最小字符数。在这种定义下,我们可以使用类似的状态转移方程来进行计算。具体的状态转移方程可以如下表示: - 当i < j时,不可能将前i个字符分割为j个子串,即dp[i][j] = INF。 - 当i >= j时,我们可以遍历所有可能的分割点k,计算dp[i][j]的最小值,即dp[i][j] = min(dp[i][j], dp[k][j-1] + cost(k+1, i)),其中cost(k+1, i)表示将子串s[k+1:i]修改为回文所需的最小字符数。 这两种定义和状态转移方程都可以用来解决动态规划分割回文串的问题,具体使用哪种方法取决于具体的问题要求和效率要求。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [动态规划解决回文串问题](https://blog.csdn.net/qq_37414405/article/details/111317301)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [动态规划解分割回文串](https://blog.csdn.net/melody157398/article/details/119769501)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值