分隔回文串-回溯与动态规划

题目描述

[131. 分割回文串]https://leetcode-cn.com/problems/palindrome-partitioning/

题解

求解所有可能的题目一般都是暴力搜索,没有什么特别的优化方法
暴力搜索重要的思想是回溯思想:

  • 从当前状态开始,依次搜索当前状态下的所有可能选择;
  • 对于每个选择,如果是结束状态,那么返回;
  • 否则,这个选择又可作为当前状态,回到第一步。
    回溯可以用递归的方法实现
    对于本题,由于要穷举所有回文子串,我们可以首先缓存所有连续子串是否是回文串,而这个过程中可以使用动态规划:
  • 首先,每个单个字符都是回文串。
  • 其次,空串也一定是回文串。
  • 最后,如果S[i+1 ~ j-1]是回文串,并且s[i]=s[j],那么s[i~j]也一定是回文串。因此s[i ~ j]是否是回文串可以由前面已经求得的更小的子串S[i+1 ~ j-1]是否是回文串,以及s[i]是否等于s[j]来
    判断。
    长度为n的字符串的连续子串一共有n×n种,因此,我们可以建立一个n×n的bool型数组isReverse[][],isReverse[i][j]如果为true,则代表s[i ~ j]是回文串。
    PS:s[i][j],当i=j或i>j是必要的。i=j时,说明单个字符一定回文,而i>j时用于判定s[i ~ i+1]是否回文,由于空串一定回文,只需判断s[i]是否等于s[i+1]。
    由于动态规划要由小的串生成大的串,我们可以从字符串末尾开始,过程演示如下:

    建立了以上判断数组后,就可以搜索了。
    部分搜索过程如下:

    代码:
class Solution {
    List<List<String>> ans = new ArrayList();
    boolean[][] isReverse;
    List<String> cur = new ArrayList();
    public List<List<String>> partition(String s) {
            int n = s.length();
            isReverse = new boolean[n][n];
            for(int i=0;i<n;i++){
                Arrays.fill(isReverse[i],true);
            }
            for(int i=n-1;i>=0;i--){
                for(int j=i+1;j<n;j++){
                    isReverse[i][j]=(s.charAt(i)==s.charAt(j))&&isReverse[i+1][j-1];
                }
            }
            dfs(s,0,n);
            return ans;
    }
    private void dfs(String s,int begin,int len){
        if(begin==len){
            ans.add(new ArrayList<String>(cur));//一定要new一个,否则后续改变cur,ans里面也会改变
            return ;
        }
        for(int i=begin;i<len;i++){
            if(isReverse[begin][i]){
                cur.add(s.substring(begin,i+1));
                dfs(s,i+1,len);
                cur.remove(cur.size()-1);
            }
        }
    }
}
posted @ 2021-03-07 22:31  HickeyZhang  阅读(79)  评论(0编辑  收藏  举报