0
点赞
收藏
分享

微信扫一扫

【LeetCode】剑指 Offer II 086. 分割回文子字符串

雷亚荣 2022-03-30 阅读 54

剑指 Offer II 086. 分割回文子字符串

题解

这题对于我而言,还是挺有难度的,学习了某位大神的做法

当我想到罗列出该字符串的所有回文子串后,我就卡住了,因为我想的回文子串是用一维的数组去表示的,没想到这里居然是可以用二维数组去表示的,如果可以想到二维数组应该就很容易想到对二维数组进行DFS

🚩这里还有一个“小心机”,我们用二维数组去记录i~j是否是回文时,可以不用1/0或者布尔类型去标识,直接用截取出来的回文子串,因为在我们需要频繁地用到回文子串,每次都通过切割的方式去获取效率有点低

📝代码如下:

	List<String[]> combinations = new ArrayList<>();
    String[][] palindromeArray;

    /**
     * @param s
     * @return java.lang.String[][]
     * @author 瞿莹莹
     * @describe: 我模仿大神的做法
     * @date 2022/3/28 8:35
     */
    public String[][] partition(String s) {
        // 字符串的长度
        int len = s.length();
        // 构建所有回文子串二维数组,数组的i行j列的值如果有,则说明字符串i到j是一个回文子串,且这个值就是这个回文子串
        palindromeArray = new String[len][len];
        buildPalindromeArray(s, len);
        // 深度遍历回文子串二维数组,找出回文子串可以构成原来字符串的组合
        dfsPalindromeArray(len, 0, new ArrayList<>());
        // 返回结果
        return combinations.toArray(new String[combinations.size()][len]);
    }

    /**
     * @param s
     * @param len
     * @return void
     * @author 瞿莹莹
     * @describe: 构建所有回文子串二维数组
     * @date 2022/3/28 8:43
     */
    public void buildPalindromeArray(String s, int len) {
        // 因为字符串的访问用的是charAt,且在循环中需要频繁访问,没有数组访问地快,所以将字符串用数组表示
        char[] strArray = s.toCharArray();

        // 从后面开始遍历字符串
        for (int i = len - 1; i >= 0; i--) {
            // 从这一位开始向后看,因为这一位的后一位在上一个循环中已经整理好了,我们可以借助它来判断这一位打头时是否可以找到回文
            for (int j = i; j < len; j++) {
                // i是子串head,j是子串tail,判断i~j是否是回文,
                // 在head和tail字符相等的情况下,可以借助i+1~j-1是否是回文,
                // 但是需要注意看i和j是否是相邻的 或者 i和j是否就是一个位置
                if (strArray[i] == strArray[j] && (j - i <= 1 || palindromeArray[i + 1][j - 1] != null)) {
                    palindromeArray[i][j] = s.substring(i, j + 1);
                }
            }
        }
    }

    /**
     * @param len
     * @param combination
     * @return void
     * @author 瞿莹莹
     * @describe: 深度遍历回文子串二维数组
     * @date 2022/3/28 9:05
     */
    public void dfsPalindromeArray(int len, int rowIndex, List<String> combination) {
        // 一次深度遍历的最后一层,就是发现上面行都遍历过了,这次要从最后一行的下一行开始遍历了
        if (rowIndex >= len) {
            // 说明dfs遍历完了,已经找到了一个回文组合
            combinations.add(combination.toArray(new String[combination.size()]));
            return;
        }

        // 遍历这一行的元素,对其的没有个非空元素进行dfs
        // 这个矩阵数组是一个上三角数组,因为下三角部分表示的是i>j的部分,而在构建回文子串二维数组的时候,是从i<j的情况下考虑的
        // 所以只需要遍历上三角
        for (int j = rowIndex; j < len; j++) {
            if (palindromeArray[rowIndex][j] != null) {
                combination.add(palindromeArray[rowIndex][j]);
                // 下一个深度遍历的rowIndex应该是这一个非空元素的所在列数+1
                dfsPalindromeArray(len, j + 1, combination);
                // 为这一行的下一个元素准备一个正确的组合(combination),删除这一行加入的新元素,也就是最后一个元素
                // 为什么这里新加入的元素是最后一个元素,是因为上一步代码执行完成后,其他后加入list的元素都是已经访问完毕的状态,
                // 访问完毕的数据就会从combination中移出去,因此到这一步时,这一行加入的元素就成了combination的最后一个元素
                combination.remove(combination.size() - 1);
            }
        }
    }

🏴‍☠️重点理解combination.remove(combination.size() - 1);这段代码,为什么是删除最后一个元素。

总结心得

  • 题目给的数据肯定需要遍历,遍历的过程中总结规律并且记录规律,记录规律的媒介有很多种,比如一维数组、二维数组等等,如果一维数组解决不了问题,就可以试着想到二维数组
  • 对我们记录的规律又需要一次遍历,这次遍历是为了得到结果,拿二维数组来说,遍历的方式有很多种,比如DFS,BFS,循环枚举
  • 当我们遍历一个东西的时候(可以是数据,也可以是我们从数据总结出来的规律),要从两个角度去思考,如果从head开始遍历不方便,那就从tail开始遍历,比如这题回文明显从后面开始遍历比较好,这题从后开始遍历然后就是动态规划的思想

Java知识UP

  • String类型->Array类型:String类型变量的toCharArray方法,没有参数
  • List类型->Array类型:List类型的toArray方法,参数比较特别,如果list里面的每一项是String[]类型的话,那就是一个二维数组,参数就可以是new String[rowNum][colNum],感觉参数就是一个新的数组实例
  • List删除某个元素可以用它的remove方法,参数就是那个元素的index
举报

相关推荐

0 条评论