给你一个字符串 s ,你需要将它分割成一个或者更多的 平衡 子字符串。比方说,s == “ababcc” 那么 (“abab”, “c”, “c”) ,(“ab”, “abc”, “c”) 和 (“ababcc”) 都是合法分割,但是 (“a”, “bab”, “cc”) ,(“aba”, “bc”, “c”) 和 (“ab”, “abcc”) 不是,不平衡的子字符串用粗体表示。
请你返回 s 最少 能分割成多少个平衡子字符串。
样例:
输入:s = “fabccddg”
输出:3
解释:
我们可以将 s 分割成 3 个子字符串:(“fab, “ccdd”, “g”) 或者 (“fabc”, “cd”, “dg”) 。
按照动态规划的思路来看, 把问题分割成一个个的子问题
假设dp[i] 表示s[i..]平衡子字符串的最少个数, 那么dp[i-1] = min(dp[i] + 1, if 可以得到平衡子字符串 dp[i+1], dp[i+2], .. dp[n])
问题在于如何判断s[i..j] 是否是一个平衡子字符串
实现一个check函数
1 2 3 4 5 6 7
| fn check(chars: &Vec<char>, i: usize, j: usize) -> bool{ let mut cnt = HashMap::new(); for k in i..j{ *cnt.entry(chars[k]).or_insert(0) += 1; } cnt.values().max() == cnt.values().min() }
|
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| use std::collections::{HashMap};
pub struct Solution; impl Solution { pub fn minimum_substrings_in_partition(s: String) -> i32 { fn check(chars: &Vec<char>, i: usize, j: usize) -> bool{ let mut cnt = HashMap::new(); for k in i..j{ *cnt.entry(chars[k]).or_insert(0) += 1; } cnt.values().max() == cnt.values().min() } let len = s.len(); let mut dp:Vec<i32> = (0..len as i32 +1).collect(); let chars: Vec<char> = s.chars().collect(); for i in 1..len+1{ dp[i] = dp[i].min(dp[i-1] + 1); for j in 0..i{ if check(&chars, i, j){ dp[i] = dp[i].min(dp[j]); } } } dp[len] } }
|
但是使用check函数会超时
进一步优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| use std::collections::HashMap; impl Solution { pub fn minimum_substrings_in_partition(s: String) -> i32 { let len = s.len(); let mut dp: Vec<i32> = (0..len as i32 + 1).collect(); let chars: Vec<char> = s.chars().collect(); for i in 1..len { let mut cnt = HashMap::new(); for j in (0..i+1).rev() { *cnt.entry(chars[j]).or_insert(0) += 1; if cnt.values().max() == cnt.values().min() { dp[i+1] = dp[i+1].min(dp[j] + 1); } } } dp[len] } }
|