【LetMeFly】3144.分割字符频率相等的最少子字符串:动态规划+哈希表
力扣题目链接:https://leetcode.cn/problems/minimum-substring-partition-of-equal-character-frequency/
给你一个字符串 s
,你需要将它分割成一个或者更多的 平衡 子字符串。比方说,s == "ababcc"
那么 ("abab", "c", "c")
,("ab", "abc", "c")
和 ("ababcc")
都是合法分割,但是 ("a", "bab", "cc")
,("aba", "bc", "c")
和 ("ab", "abcc")
不是,不平衡的子字符串用粗体表示。
请你返回 s
最少 能分割成多少个平衡子字符串。
注意:一个 平衡 字符串指的是字符串中所有字符出现的次数都相同。
示例 1:
输入:s = "fabccddg"
输出:3
解释:
我们可以将 s
分割成 3 个子字符串:("fab, "ccdd", "g")
或者 ("fabc", "cd", "dg")
。
示例 2:
输入:s = "abababaccddb"
输出:2
解释:
我们可以将 s
分割成 2 个子字符串:("abab", "abaccddb")
。
提示:
1 <= s.length <= 1000
s
只包含小写英文字母。
解题方法:动态规划
使用一个动态规划数组$dp$,其中$dp[i]$代表字符串$s$的前$i$个字符最少能分割成多少个平衡子字符串。初始值除了$dp[0]=0$外都是“无穷大”。
接着使用下标$i$从前往后遍历字符串。假设字符串的$j$到$i$子串是平衡字符串,那么有$dp[i + 1] = \min (dp[i + 1], dp[j] + 1)$。
对于一个下标$i$,如何判断是否存在一个$j\lt i$,使得$j$到$i$的子串是平衡字符串呢?我们可以使用$j$从$i$往前开始遍历字符串,并使用一个哈希表统计每个字符出现的次数,再使用两个变量$types$和$maxTimes$分别统计$j$到$i$的子串中字符种类数和字符最大出现次数。如果$字符种类数\times 字符最大出现次数=子串长度$,就说明子串是平衡字符串(每个字符出现次数相等,都是$maxTimes$次)。
- 时间复杂度$O(len(s)^2)$
- 空间复杂度$O(len(s) + C)$,其中$C$是字符种类数,$C=26$
AC代码
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class Solution { public: int minimumSubstringsInPartition(string& s) { vector<int> dp(s.size() + 1, 1000000); dp[0] = 0; unordered_map<char, int> ma; for (int i = 0; i < s.size(); i++) { ma.clear(); int types = 0, maxTimes = 0; for (int j = i; j >= 0; j--) { maxTimes = max(maxTimes, ++ma[s[j]]); if (ma[s[j]] == 1) { types++; } if (maxTimes * types == i - j + 1) { dp[i + 1] = min(dp[i + 1], dp[j] + 1); } } } return dp.back(); } };
|
Go
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 30 31 32 33 34 35 36 37 38 39 40
| package main
func min(a int, b int) int { if (a > b) { return b } return a }
func max(a int, b int) int { if (a < b) { return b } return a }
func minimumSubstringsInPartition(s string) int { dp := make([]int, len(s) + 1) for i := range dp { dp[i] = 100000 } dp[0] = 0 for i := range s { ma := map[byte]int{} types, maxTimes := 0, 0 for j := i; j >= 0; j-- { ma[s[j]]++ maxTimes = max(maxTimes, ma[s[j]]) if ma[s[j]] == 1 { types++ } if types * maxTimes == i - j + 1 { dp[i + 1] = min(dp[i + 1], dp[j] + 1) } } } return dp[len(s)] }
|
Java
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
| import java.util.Map; import java.util.HashMap; import java.util.Arrays;
class Solution { public int minimumSubstringsInPartition(String s) { int[] dp = new int[s.length() + 1]; Arrays.fill(dp, 100000); dp[0] = 0; Map<Character, Integer> ma = new HashMap<Character, Integer>(); for (int i = 0; i < s.length(); i++) { ma.clear(); int types = 0, maxTimes = 0; for (int j = i; j >= 0; j--) { int originalTimes = ma.getOrDefault(s.charAt(j), 0); ma.put(s.charAt(j), originalTimes + 1); maxTimes = Math.max(maxTimes, originalTimes + 1); if (originalTimes == 0) { types++; } if (maxTimes * types == i - j + 1) { dp[i + 1] = Math.min(dp[i + 1], dp[j] + 1); } } } return dp[s.length()]; } }
|
Python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| from collections import defaultdict
class Solution: def minimumSubstringsInPartition(self, s: str) -> int: dp = [100000] * (len(s) + 1) dp[0] = 0 ma = defaultdict(int) for i in range(len(s)): ma.clear() types, maxTimes = 0, 0 for j in range(i, -1, -1): ma[s[j]] += 1 maxTimes = max(maxTimes, ma[s[j]]) if ma[s[j]] == 1: types += 1 if maxTimes * types == i - j + 1: dp[i + 1] = min(dp[i + 1], dp[j] + 1) return dp[-1]
|
同步发文于CSDN和我的个人博客,原创不易,转载经作者同意后请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/141652980