回溯(分割)

237 阅读2分钟

分割回文串

题目:131

  • 一眼望去,难点大概就是:如何分割,判断是否为回文串
  • 先挨个切割,然后再判断目前切割到的字符串是否为回文串,切记回溯的本质也是穷举
  • 判定是否为回文串,利用双指针,头尾两指针相互靠近然后判断是不是同一字符就行,不用多说
  • 如果是回文串,就加入deque这个单元答案,如果不是,继续增大结束位置
  • 每遍历一次字符串s就是一组分割方案,同一层的遍历,起始位置不变,就是传入的startIndex,到下一层的时候,为了保证不重复,起始位置 + 1
  • 如果起始位置 > 字符串长度,说明已经走到了一棵树的分支终点,找到了一组分割方案。
        if (startIndex >= s.length()) {
            lists.add(new ArrayList<>(deque));
            return;
        }
  • 关于模拟切割线,其实就是index是上一层已经确定了的分割线,i是这一层试图寻找的新分割线
       for (int i = startIndex; i < s.length(); i++) {
            //如果是回文子串,则记录
            if (isPalindrome(s, startIndex, i)) {
                String str = s.substring(startIndex, i + 1);
                deque.addLast(str);
            } else {
                continue;
            }
            //起始位置后移,保证不重复
            backTracking(s, i + 1);
            deque.removeLast();
        }

复原IP地址

题目:93

  • 更难了......还需要操作字符串添加逗号作为分隔符,回溯的话,也是直接删掉最后的分组,不单纯是一个元素了
  • 先想法判断一个段位是否是有效段位
    • 段位以0为开头的数字不合法
    • 段位里有非正整数字符不合法
    • 段位如果大于255了不合法
//一个段位最长为3,且表示的数字在[0,255]之间
       for (int i = start; i < s.length() && i - start < 3 
                && Integer.parseInt(s.substring(start, i + 1)) >= 0
                && Integer.parseInt(s.substring(start, i + 1)) <= 255; i++) {
            //段位以0开头的数字
            if (i + 1 - start > 1 && s.charAt(start) - '0' == 0) {
                continue;
            }
        }
  • 返回值以及参数:切割问题要有一个开始索引startIndex(感觉每个回溯问题都有个它......)然后因为要加入'.'作为分隔符对字符串进行一个分组,引入表示当前分组数的参数number

public void restoreIpAddressesHandler(String s, int start, int number)

  • 终止条件:符合条件的分组完成,把这一个答案添加到答案集合里,然后返回。或者分组还没按规矩完成:开始索引start先到了字符串结尾,但还没有分完四组。 分完了四组,但是还没有把字符串都分完。这时候返回,继续找寻正确的分组。
       if (start == s.length() && number == 4) {
            result.add(stringBuilder.toString());
            return;
        }

        if (start == s.length() || number == 4) {
            return;
        }
  • 单层递归逻辑:不要忘记,回溯的本质就是穷举,就是从0开始一个一个试,从假设刚开始的分组只有一个数开始不断穷举,错了没事,反正可以return重来。主要是进入下一层递归和回溯的边界值
            if (number < 3) {
                stringBuilder.append(".");
            }
            number++;
            restoreIpAddressesHandler(s, i + 1, number);
            //这里是就算加了'.'但是开头索引是i+1,不是i+2
            //因为原本的字符串s里并没有加'.',加逗号的是之前创建的stringbuilder结构
            
            number--;
            stringBuilder.delete(start + number, i + number + 2);
            //去掉一个分组,在stringbuilder里,如果不在意之前的逗号数量的话,应该是(start, i + 2)
            //因为还是要包含一下新加入的'.'的,而且右边界是开区间,这样正好把之前新加的'.'去掉。
            //现在再考虑一下之前加的逗号,所以就成为了(start + number, i + number + 2)
            //毕竟......现在的start i 是用来取原字符串s里的值的,而原字符串里没有'.'