11月11日 最少字符串操作次数
问题描述
小U得到一个只包含小写字母的字符串 S。她可以执行如下操作:每次选择字符串中两个相同的字符删除,然后在字符串末尾添加一个任意的小写字母。小U想知道,最少需要多少次操作才能使得字符串中的所有字母都不相同?
思考
由于题目问的是最少需要多少次操作才能使得字符串中的所有字母都不相同,我们可以使用一个字典统计每个字符在字符串中出现的次数。如果某个字符出现 count 次,则它会多出 count - 1 次重复。 每次操作可以减少 2 个重复字符,因此对每个字符,最少需要 (count - 1) // 2 次操作来清理多余的字符。之后我们再将所有字符的重复清理操作次数相加,得到最少操作数。如果没有重复字符,就无需任何操作。
代码
def solution(S: str) -> int: # 统计每个字符的频率 frequency = {} for char in S: frequency[char] = frequency.get(char, 0) + 1 # 计算需要的最小操作次数 operations = 0 for count in frequency.values(): operations += count // 2 # 每两个重复字符需要一次操作 return operations
感想
本题综合了字符串统计和贪心算法的思想,通过减少重复字符的方式解决问题。我们可以在解题过程中深刻体会到如何使用字典高效统计,同时合理推导出最少操作数的计算方法,具有实用性。
11月12日 最大矩形面积问题
问题描述
小S最近在分析一个数组 h1 , h2 , . . . , hN ,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 k 个相邻元素时,如何计算它们所能形成的最大矩形面积。 对于 k 个相邻的元素,我们定义其矩形的最大面积为:R(k)=k×min(h[i],h[i+1],...,h[i+k−1])
即R(k) 的值为这 k 个相邻元素中的最小值乘以 k。现在,小S希望你能帮他找出对于任意 k, R(k) 的最大值。
思考
这是一个非常经典的直方图最大矩形问题,通过找到每个高度的最大宽度并计算面积,从中找出最大的矩形面积。小S的要求是找到数组中任意相邻 k 个元素所能形成的最大矩形面积,其公式为 R(k)=k×min(h[i],h[i+1],…,h[i+k−1])。
由于直方图问题的性质,可以用单调栈来高效解决。我们可以选择在数组两端添加一个高度为 0 的“哨兵”元素,便于处理边界问题。
单调栈是一种特殊的栈,它具有以下特点:
- 单调递增栈:栈内元素保持从栈底到栈顶单调递增(即每个新元素都大于或等于栈顶元素)。
- 单调递减栈:栈内元素保持从栈底到栈顶单调递减(即每个新元素都小于或等于栈顶元素)。
核心思想:通过维护栈内元素的单调性,在遍历数组的过程中,快速找到每个元素左右两侧第一个更大(或更小)的元素。
应用场景:
-
找某元素左右两边第一个更大/更小的元素,经典问题如"下一个更大元素"、"柱状图中最大矩形面积"。
-
区间范围内的最大/最小值问题,经典问题如滑动窗口最大值、最小值问题。
-
动态维护范围内的最优值,经典问题如计算 雨水接水问题。
代码
def solution(n, array): # 在原数组两端添加哨兵元素0,以方便计算 array = [0] + array + [0] stack = [] max_area = 0 # 遍历每个位置,计算以每个高度为最小值的最大矩形面积 for i in range(len(array)): # 当当前高度小于栈顶高度时,计算栈顶高度的最大矩形面积 while stack and array[i] < array[stack[-1]]: height = array[stack.pop()] width = i - stack[-1] - 1 # 计算当前高度的宽度 max_area = max(max_area, height * width) stack.append(i) return max_area
感想
单调栈是一种非常高效的数据结构,能够解决许多类似问题(如雨水接水问题、滑动窗口)。在这里,通过使用单调栈高效地解决了矩形面积计算的问题,同时通过引入“哨兵”优化了边界条件处理,代码更加简洁清晰。本题中我们可以了解,单调栈可以通过维护栈内元素的单调性,可以高效地解决问题,避免暴力枚举的复杂性。
11月13日 小D的`abc` 变换问题
问题描述
小D拿到了一个仅由 "abc" 三种字母组成的字符串。她每次操作会对所有字符同时进行以下变换: 将 'a' 变成 'bc' 将 'b' 变成 'ca' 将 'c' 变成 'ab' 小D将重复该操作 k 次。你的任务是输出经过 k 次变换后,得到的最终字符串。 例如:对于初始字符串 "abc",执行 2 次操作后,字符串将变为 "caababbcbcca"。
思考
这是一个递归替换问题,小D的字符串在每次操作中,会根据规则将每个字符扩展为长度为 2 的新字符串。随着操作次数 k 的增加,字符串的长度将以指数级增长。对于较大的k,直接拼接字符串可能导致内存不足或运行超时,因此需要优化计算方法。
如果我们选择展开多次,可以发现每次变换后的字符串内容遵循一定的模式,可以用公式递归计算。
代码
def solution(s: str, k: int) -> str: # 定义映射关系 transform = {'a': 'bc', 'b': 'ca', 'c': 'ab'} # 执行 k 次变换 for _ in range(k): s = ''.join(transform[char] for char in s) # 对每个字符进行变换并拼接成新字符串 return s
感想
本题是通过直接模拟可能会导致性能问题,而通过递归或分治思想可以显著优化计算。递归解决的关键是找到字符变换的模式和规律,从而避免冗余计算。