LEETCODE 1278. Palindrome Partitioning III 解题思路分析

题目大意:

分割回文串 III

给你一个由小写字母组成的字符串 s,和一个整数 k。

请你按下面的要求分割字符串:

首先,你可以将 s 中的部分字符修改为其他的小写英文字母。
接着,你需要把 s 分割成 k 个非空且不相交的子串,并且每个子串都是回文串。
请返回以这种方式分割字符串所需修改的最少字符数。

示例 1:

输入:s = "abc", k = 2
输出:1
解释:你可以把字符串分割成 "ab" 和 "c",并修改 "ab" 中的 1 个字符,将它变成回文串。 

示例 2:

输入:s = "aabbc", k = 3
输出:0
解释:你可以把字符串分割成 "aa"、"bb" 和 "c",它们都是回文串。

示例 3:

输入:s = "leetcode", k = 8
输出:0

提示:

  • 1 <= k <= s.length <= 100
  • s 中只含有小写英文字母。

如果想查看本题目是哪家公司的面试题,请参考以下免费链接: https://leetcode.jp/problemdetail.php?id=1278

解题思路分析:

典型的动态规划(DP),或者说是递归加记忆数组的题目。为什么说是典型,原因在于,我们无法一眼算出如何分割字符串能够得到最优解,这种情况下,通常我们需要遍历所有分割可能,然后比较出一个最优解作为返回结果。

我们先从字符串头部开始分割出第一部分,该部分的长度范围在1到字符串长度length – k(k是剩下要分割的个数)之间。比如,字符串长度为5,我们要将其分成3部分,那么第一部分的最小长度可以为1 ([0, 0]区间),最大长度只能为3,即[0, 2]区间(length-k=5-3=2),如果第一部分大于这个长度,那么剩下的元素就无法满足总的分割次数。我们从最小长度遍历到最大长度,分别计算出当前子字符串变为回文所需的更改次数,然后再加上剩下的部分完全分割后所需的最小次数,取最小值即为当前的返回结果。剩下部分的分割可以交给子问题去解决(递归),子问题的处理逻辑与当前相同。递归结束条件是当子字符串长度等于k时,返回0(将长度为k的字符串分成k部分,每部分长度为1,都是回文,无需更改)。另外,如果字符串长度小于k,也可以返回0。(无法分割,属于不合理解)

另外需要注意一点,如果当前的k值为1时,也就是说我们别无选择,当前字符串是不能分割的。

实现代码:

Integer[][] memo; // 记忆数组
public int palindromePartition(String s, int k) {
    memo = new Integer[s.length()][k+1];
    return help(s,k,0); // 递归求解
}
// s为字符串
// k为分割数
// left为当前index
int help(String s, int k, int left){
    // 如果当前index到字符串末尾小于等于k,返回0(解释看上文)
    if (s.length()-left<=k) return 0;
    // 如果记忆数组不为空,直接返回
    if(memo[left][k]!=null) return memo[left][k];
    // 返回结果
    int res=Integer.MAX_VALUE;
    // 如果当前k为1时,无法分割,右区间直接设置到字符串末尾
    // 反之,左区间指针等于右区间指针(区间长度为1)
    int right =k==1?s.length()-1:left;
    // 循环当前分割的可能长度范围[left, right(i)]
    for(int i=right;i<=s.length()-k;i++){
        // 当前分割区间是[left, i]
        int l =left,r=i;
        // 计算将该区间变成回文需要变换的次数
        int count =0;
        while(l<r){
            if(s.charAt(l++)!=s.charAt(r--)) count++;
        }
        // 如果次数大于等于之间计算的最小值,继续
        if(count>=res) continue;
        // 当前区间变换次数加上后面部分需要变换的次数为当前解
        // 更新最小值为当前最优解
        res=Math.min(res, count+help(s,k-1,i+1));
    }
    memo[left][k]=res; // 将结果存入记忆数组
    return res;
}

本题解法执行时间为4ms。

Runtime: 4 ms, faster than 90.85% of Java online submissions for Palindrome Partitioning III.

Memory Usage: 34.1 MB, less than 100.00% of Java online submissions for Palindrome Partitioning III.

本网站文章均为原创内容,并可随意转载,但请标明本文链接
如有任何疑问可在文章底部留言。为了防止恶意评论,本博客现已开启留言审核功能。但是博主会在后台第一时间看到您的留言,并会在第一时间对您的留言进行回复!欢迎交流!
本文链接: https://leetcode.jp/leetcode-1278-palindrome-partitioning-iii-解题思路分析/
此条目发表在leetcode分类目录,贴了, , , , 标签。将固定链接加入收藏夹。

发表评论

您的电子邮箱地址不会被公开。