力扣记录:回溯算法2分割——131 分割回文串,93 复原IP地址

本次题目

  • 131 分割回文串
  • 93 复原IP地址

131 分割回文串

  • 回文串:正读和反读都一样的字符串,可以使用双指针分别从前后向两边移动判断。
  • 回溯:
    1. 定义全局变量(双向队列)存放回文子串,定义全局二维数组存放回文子串集合,使用双向队列定义for循环开始位置防止重复;
    2. 遍历完字符串后终止;
    3. 从startIndex位置(下一次遍历的开始位置)到for循环的i位置(左闭右闭,下次切割从i+1开始)不断切割,如果切割的子串是回文子串,则添加到双向队列中,否则直接跳过。
  • 注意:字符串切割操作可以放到判断回文子串中。字符串切割(左闭右开)substring(start,end)。双向队列转为列表LinkedList(),都是用LinkedList容器。
class Solution {
    //定义全局变量(双向队列)存放回文子串,定义全局二维数组存放回文子串集合
    Deque<String> deque = new LinkedList();
    List<List<String>> result = new LinkedList<>();
    public List<List<String>> partition(String s) {
        //使用startIndex定义for循环开始位置防止重复
        int startIndex = 0;
        //开始回溯
        backtracking(s, startIndex);
        //返回结果
        return result;
    }
    //回溯函数
    private void backtracking(String s, int startIndex){
        //遍历完字符串后终止
        if(startIndex > s.length() - 1){
            //栈转为List
            result.add(new LinkedList(deque));
            return;
        }
        //从startIndex位置(下一次遍历的开始位置)
        //到for循环的i位置(左闭右闭,下次切割从i+1开始)不断切割
        for(int i = startIndex; i < s.length(); i++){
            //如果切割的子串是回文子串,则添加到双向队列中,否则直接跳过
            if(isPalindrome(s, startIndex, i)){
                String res = s.substring(startIndex, i + 1);
                deque.addLast(res);
            }else{
                continue;
            }
            //回溯
            backtracking(s, i + 1);
            deque.removeLast();
        }
    }
    //判断回文串
    private boolean isPalindrome(String s, int start, int end){
        //使用双指针分别从前后向两边移动判断
        for(int i = start, j = end; i < j; i++, j--){
            if(s.charAt(i) != s.charAt(j)) return false;
        }
        return true;
    }
}

93 复原IP地址

  • 回溯:同上131 分割回文串,切割后判断是否满足ip地址的要求(<255)。
    1. 定义全局数组存储结果集合,由于不能重复分割,定义startIndex记录下一个for循环的起始位置,定义整数记录添加的点的数量(满足ip地址后已分割的次数);
    2. 当添加三个点(分割三次)时终止,此时若最后一段满足条件则将整个字符串(加点后)添加到结果集合中;
    3. 分割时同上131 分割回文串,分割范围为startIndex到i区间(左闭右闭),如果满足条件则在分割字符串后加上“.”,不满足条件则直接退出本次for循环,递归时下一次递归起始位置为i+2(因为在i+1添加了“.”)。
  • 注意:判断分割的子串是否满足条件
    1. 不能以0开头(只有一个0是可以的);
    2. 不能有数字以外的其他字符;
    3. 不能大于255(注意防止溢出)。
class Solution {
    //定义全局数组存储结果集合
    List<String> result = new LinkedList<>();
    public List<String> restoreIpAddresses(String s) {
        //由于不能重复分割,定义startIndex记录下一个for循环的起始位置
        int startIndex = 0;
        //定义整数记录添加的点的数量(满足ip地址后已分割的次数)
        int pointNum = 0;
        //开始回溯
        backtracking(s, startIndex, pointNum);
        //返回结果
        return result;
    }
    //回溯函数
    private void backtracking(String s, int startIndex, int pointNum){
        //当添加三个点(分割三次)时终止
        if(pointNum == 3){
            //此时若最后一段满足条件则将整个字符串(加点后)添加到结果集合中
            if(judgeIP(s, startIndex, s.length() - 1)) result.add(s);
            return;
        }
        //此处进行剪枝,i上限为3位,超过三位肯定超过255
        for(int i = startIndex; i < Math.min(s.length(),startIndex + 3); i++){
            //分割范围为startIndex到i区间(左闭右闭)
            //如果满足条件则在分割字符串后加上“.”,不满足条件则直接退出本次for循环
            if(judgeIP(s, startIndex, i)){
                s = s.substring(0, i + 1) + "." + s.substring(i + 1, s.length());
                pointNum++;
                //回溯
                //递归时下一次递归起始位置为i+2(因为在i+1添加了“.”)
                backtracking(s, i + 2, pointNum);
                s = s.substring(0, i + 1) + s.substring(i + 2, s.length());
                pointNum--;
            }else{
                break;
            }
        }
    }
    //判断分割的子串是否满足条件
    private boolean judgeIP(String s, int left, int right){
        //防止溢出
        if(right - left > 2) return false;
        //当左边界大于右边界时返回false,此时点后无数
        if(left > right) return false;
        //(1)不能以0开头;
        if(s.charAt(left) == '0' && left != right) return false;
        //(2)不能有数字以外的其他字符;
        int num = 0;
        for(int i = left; i <= right; i++){
            if(s.charAt(i) < '0' || s.charAt(i) > '9') return false;
            num = num * 10 + (s.charAt(i) - '0');
        }
        //(3)不能大于255。
        //当数字很大时溢出导致此处判断失败。在开头增加判断,超过三位则直接返回false
        if(num > 255) return false;
        return true;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值