You are given a string s containing lowercase letters and an integer k. You need to :

  • First, change some characters of s to other lowercase English letters.
  • Then divide s into k non-empty disjoint substrings such that each substring is palindrome.

Return the minimal number of characters that you need to change to divide the string.

Example 1:
Input: s = "abc", k = 2
Output: 1
Explanation: You can split the string into "ab" and "c", and change 1 character in "ab" to make it palindrome.

Example 2:
Input: s = "aabbc", k = 3
Output: 0
Explanation: You can split the string into "aa", "bb" and "c", all of them are palindrome.

Example 3:
Input: s = "leetcode", k = 8
Output: 0

Constraints:

  • 1 <= k <= s.length <= 100.
  • s only contains lowercase English letters.

给一个由小写字母组成的字符串s,和一个整数k
按下面的要求分割字符串:

  1. s中的部分字符修改为其他的小写英文字母。
  2. s分割成k个非空且不相交的子串,且每个子串都是回文。

返回以这种方式分割字符串所需修改的最少字符数。
这个问题和切割钢条比较相似
定义函数f(r,t)表示字符串s[0:r]分成t段最少需要的次数,那么

f(r, t) = min { f(i, t − 1) + check(i + 1, r) }
其中 i ∈ [0,n],而check函数用于检查将字符串s[i+1:r]所需要的最少次数。

check函数实现也非常容易,我们可以先定义两个指针lr分别指向字符串的首尾,然后将左右指针向中间靠拢,判断左右指针指向的字符是不是相同,不相同的话就需要改变一次。
和钢条切割的区别:

  • check函数就可以看成切割钢条的price表.只不过price表是直接给出的,check函数需要自己实现

回顾一下钢条切割的朴素递归的伪代码:
image.png
写出朴素递归:

// 朴素递归  
public int palindromePartition1(String s, int k) {
    return dfs(s, s.length() - 1, k);
}

private int dfs(String s, int r, int t) {
    if (t == 1) return count(s,0, r);
    int res = Integer.MAX_VALUE;
    for (int i = 0; i <= r; i++) {
        res = Math.min(res, dfs(s, i, t - 1) + count(s, i + 1, r));
    }
    return res;
}
private int count(String s, int left, int right) {  
    int c = 0;  
    while (left < right) {  
        if (s.charAt(left++) != s.charAt(right--)) c++;  
    }  
    return c;  
}

根据朴素递归,增加memo参数,即可得到带memo的记忆化递归:

// 带memo的递归
public int palindromePartition2(String s, int k) {
    Integer[][] memo = new Integer[s.length() + 1][k + 1];
    return dfsWithMemo(s, s.length() - 1, k, memo);
}

private int dfsWithMemo(String s, int r, int t, Integer[][] memo) {
    if (t == 1) return count(s, 0, r);
    if (memo[r][t] != null) return memo[r][t];
    int res = Integer.MAX_VALUE;
    for (int i = 0; i <= r; i++) {
        res = Math.min(res, dfsWithMemo(s, i, t - 1, memo) + count(s, i + 1, r));
    }
    memo[r][t] = res;
    return res;
}
https://coordinate.wang/index.php/archives/2791/

proheart
41 声望20 粉丝

Developer, Java & Android


引用和评论

0 条评论