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 a 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, 以 s[i]作为回文的中心点, 分别向左右扩展,得到一系列 substring, 我们可以很方便的计算出每个 substring 变成回文所需要替换的字符数量, 我们将这些 substring 和数量保存到一个 HashMap 中, 然后我们再遍历一次,计算出所有以 s[i…i+1]为中心的 substring 及其所需要的替换的字符数量,同样保存到同一个 HashMap 中。这时我们就已经把 s 的所有 substring 都算出来了。剩下的工作就是用 dp 算法算出答案。具体表示为 dp[i][k]为将 s[i…]切分成 k 块所需的最小替换数量。假设 m[s[i…=j]]为 substring s[i…=j]所需的替换数量, 那么 dp[i][k] = min(m[s[i…=i]] + dp[i+1][k-1], m[s[i…=i+1]] + dp[i+2][k-1], …, m[s[i…=n-1]] + dp[i+n][k-1]), 其中 n 为 length(s[i…])
use std::collections::HashMap;
impl Solution {
fn dp(
chars: &Vec<char>,
i: usize,
k: i32,
m: &HashMap<String, i32>,
cache: &mut HashMap<(usize, i32), i32>,
) -> i32 {
if i == chars.len() {
if k == 0 {
return 0;
}
return i32::MAX;
}
if k == 0 {
return i32::MAX;
}
let mut ans = i32::MAX;
for j in i..chars.len() {
let s = chars[i..=j].into_iter().collect::<String>();
let c = *m.get(&s).unwrap();
let next = if let Some(nc) = cache.get(&(j + 1, k - 1)) {
*nc
} else {
Solution::dp(chars, j + 1, k - 1, m, cache)
};
if next != i32::MAX {
ans = ans.min(c + next);
}
}
cache.insert((i, k), ans);
return ans;
}
pub fn palindrome_partition(s: String, k: i32) -> i32 {
let chars: Vec<char> = s.chars().collect();
let mut m = HashMap::new();
for i in 0..chars.len() {
let mut l = i as i32;
let mut r = i as i32;
let mut c = 0;
while l >= 0 && r < chars.len() as i32 {
if chars[l as usize] != chars[r as usize] {
c += 1;
}
let s = chars[l as usize..=r as usize]
.into_iter()
.collect::<String>();
m.insert(s, c);
l -= 1;
r += 1;
}
}
for i in 0..chars.len() - 1 {
let mut l = i as i32;
let mut r = (i + 1) as i32;
let mut c = 0;
while l >= 0 && r < chars.len() as i32 {
if chars[l as usize] != chars[r as usize] {
c += 1;
}
let s = chars[l as usize..=r as usize]
.into_iter()
.collect::<String>();
m.insert(s, c);
l -= 1;
r += 1;
}
}
Solution::dp(&chars, 0, k, &m, &mut HashMap::new())
}
}