回溯之分割问题

        分享完回溯解决组合问题子集问题全排列问题,这次分享利用回溯来解决分割问题。下面先给出回溯的模板代码。

private void backtracking(参数1,参数2,...){
	if(递归终止条件){
		收集结果;
		return;
	}
	for(遍历集合){
		处理;
		backtracking(参数1,参数2,...); // 递归;
		回溯;
	}
}

分割回文串

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

示例 1:
输入:s = “aab”
输出:[[“a”,“a”,“b”],[“aa”,“b”]]

class Solution {
    List<List<String>> ans = new ArrayList<>();
    List<String> path = new ArrayList<>();
    public List<List<String>> partition(String s) {
        backtracking(s, 0);
        return ans;
    }
    private void backtracking(String s, int startIndex){
        if(startIndex == s.length()){
            ans.add(new ArrayList<>(path));
            return;
        }
        for(int i = startIndex;i < s.length();i++){
            if(!isValid(s.substring(startIndex, i + 1))) continue;
            path.add(s.substring(startIndex, i + 1));
            backtracking(s, i + 1);
            path.remove(path.size() - 1);
        }
    }
    private boolean isValid(String str){
        int l = 0;
        int r = str.length() - 1;
        while(l < r){
            if(str.charAt(l++) != str.charAt(r--)){
                return false;
            }
        }
        return true;
    }
}

        首先定义了一个ans集合用于回收所有符合条件的分割子串,定义path用于收集遍历过程中分割出来的子串,如果path中子串都为回文串,则将其加入到ans中。在partition方法中调用了backtracking方法收集所有符合条件的分割子串,最终返回ans集合。isValid方法用于判断某个子串是否为回文串(如果不明白,可以看看回文串首篇)。
        利用上述示例,说明backtracking代码的执行流程。进入backtracking,startIndex等于0,不等于需要分割字符串长度,进入for循环,截取字符串aab的首个字母a,一个字母也是回文串,isValid返回true,将字母a加入到path中,path为[a],接着递归进入下一个backtracking,也是不满足if条件,进入for循环,startIndex为1,截取字符串aab的第二个字母a,为回文串,isValid返回true,将其放入path中,path为[a, a],递归进入下一个backtracking,startIndex为2,截取字符串aab的最后一个字母b,为回文串,isValid返回true,将其加入到path中,path为[a, a, b],递归进入下一个backtracking中,startIndex为3,满足if条件,因此将[a, a, b]放入ans集合中,递归返回上一个backtracking,将字符串b从path中移除,path为[a, a],for循环继续,i++,i等于3,等于字符串长度,for循环结束,递归返回上一个backtracking,将字符串a从path中移除,path为[a],for循环继续,i++,截取字符串aab中最后两个字母ab,不是回文串,isValid返回false,for循环继续,i++,等于字符串长度,for循环结束,递归返回最初的backtracking,将字母a从path中移除,path为空,for循环继续,i++,截取字符串aab中的前两个字母aa,为回文串,isValid为true,将aa放入path中,递归进入下一个backtracking,startIndex为2,截取最后一个字母b,为回文串,isValid为true,将字母b加入path中,path为[aa, b],递归进入下一个backtracking,startIndex为3,满足if条件,将[aa, b]加入ans集合中,递归返回上一个backtracking,将b从path中移除,path为[aa],for循环继续,i++后等于3,for循环结束,递归返回最初的backtracking,将aa从path中移除,for循环继续,i++,此时截取了整个字符串aab,显然不是回文串,isValid为false,for循环继续,i++后等于3,for循环结束,递归返回到partition,返回ans。
        在上述回溯代码中,关键部分在于使用了一个startIndex参数,规定了下一个递归截取的起始位置为当前递归方法遍历位置i的下一个位置i+1,需要注意的是,substring字符串截取方法截取区间是左闭右开,包含左侧,不包含右侧,因此要截取当前遍历位置i,右侧区间端点需要为i + 1。

参考:带你学透回溯算法(理论篇)| 回溯法精讲!

  • 23
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值