问题描述
小G定义了一个字符串的权值为:字符串的长度乘以字符串中不同字母的种类数量。例如,对于字符串 "abacb",其权值为 5 × 3 = 15,因为字符串的长度为 5,且包含 3 种不同的字母。
现在,小G有一个字符串,她希望将这个字符串切分成 k 个子串,并希望这些子串的最大权值尽可能小。你需要帮助小G找到最优的切分方案,使得这 k 个子串中的最大权值最小化。
测试样例 样例1:
输入:s = "ababbbb" ,k = 2 输出:6
样例2:
输入:s = "abcabcabc" ,k = 3 输出:9
样例3:
输入:s = "aaabbbcccddd" ,k = 4 输出:3
问题本质
1. 本质是一个优化问题
我们需要找到一个切分方案,使得切分出的 k 个子串中 最大权值 最小化。对于某一子串,其权值由以下公式计算:
权值=len(s)×unique(s)
其中:
len(s):子串的长度。
unique(s):子串中不同字母的种类数量。
这就要求我们在切分时,同时考虑子串长度和其字母分布的影响。
2. 结合二分查找与贪心思想
由于子串的权值与切分方式相关,我们可以通过以下步骤求解:
二分查找最大权值:假设子串的最大权值为 mid,验证是否能通过 k 次切分满足条件。
贪心验证切分可行性:尝试从头开始依次划分子串,确保每段的权值不超过 mid。
解题思路
1. 二分查找最大权值
最大权值的范围可以通过以下方式确定:
最小值:如果不进行切分,即权值为整个字符串的权值。
最大值:每个字符单独切分时,权值等于字符数(即 n×1=n)。
通过二分法,我们可以快速确定一个可行的最大权值。
2. 贪心切分验证
每次尝试切分时,计算当前子串的权值:
如果子串的权值超过 mid,则将该子串结束,并开始新的子串。
如果切分次数 >k,说明当前的 mid 不可行。
代码实现
def calculate_weight(substring):
"""计算字符串的权值"""
length = len(substring)
unique_count = len(set(substring))
return length * unique_count
def is_valid_cut(s, k, max_weight):
"""判断是否可以通过 k 次切分使得每段的权值 <= max_weight"""
count = 1
current_substring = ""
for char in s:
current_substring += char
if calculate_weight(current_substring) > max_weight:
count += 1
current_substring = char # 开始新子串
if count > k: # 切分次数超过 k
return False
return True
def minimize_max_weight(s, k):
"""使用二分查找最小化最大权值"""
left = calculate_weight(s) # 整个字符串作为一个子串的权值
right = len(s) * len(set(s)) # 每个字符独立切分的最大权值
while left < right:
mid = (left + right) // 2
if is_valid_cut(s, k, mid):
right = mid # 尝试更小的权值
else:
left = mid + 1 # 增加允许的最大权值
return left
# 测试用例
if __name__ == "__main__":
print(minimize_max_weight("ababbbb", 2)) # 输出: 6
print(minimize_max_weight("abcabcabc", 3)) # 输出: 9
print(minimize_max_weight("aaabbbcccddd", 4)) # 输出: 3
解题详解
1. 核心方法解释
(1) 权值计算
calculate_weight 函数计算任意子串的权值。通过 Python 内置的 set() 函数,我们快速获得子串中的不同字母数量。
(2) 切分验证
is_valid_cut 函数采用贪心思路,从头开始构造子串:
如果当前子串的权值超过 mid,则结束当前子串并开始新子串。 如果需要的子串数量超过 k,则返回 False。
(3) 二分查找
通过二分法缩小最大权值范围,直到找到最优解。
2. 时间复杂度分析
权值计算:每次调用 calculate_weight 的复杂度为 O(n),但实际复杂度会因子串长度较短而减少。
切分验证:对于长度为 n 的字符串,每次遍历复杂度为 O(n)。
二分查找:二分的次数为 O(log(max_weight))。
综合复杂度为 O(n×log(max_weight))。