LeetCode每日一题(Palindrome Partitioning III)

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())
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值