目录
📘 字典序最小的字符串 —— 贪心算法巧解 LeetCode 题
📘 字典序最小的字符串 —— 贪心算法巧解 LeetCode 题
在字符串和贪心算法结合的问题中,这道题是非常经典且具有代表性的一个。它不仅考察你对字符串的理解,还锻炼你构造最优解的能力。本文将深入分析一道关于构造字典序最小字符串的问题,从题目描述到代码实现再到优化与思考,帮助你真正掌握这一类型题目的解法思路。
📌 题目描述
给你两个整数 n
和 k
,请你返回长度为 n
、数值总和为 k
的 字典序最小的字符串。
- 每个字符都是小写字母(a-z)。
- 每个字符的数值等于它在字母表中的位置(a=1,b=2,c=3,…,z=26)。
- 字符串的数值是所有字符的数值之和。
- 返回的字符串必须满足:长度为
n
且数值为k
,并且是所有可能解中字典序最小的一个。
✅ 字典序的定义:
对于两个字符串 x
和 y
:
- 如果
x
是y
的前缀,则x < y
; - 如果在某一位
i
上x[i] < y[i]
,则x < y
。
🔍 示例说明
示例 1:
输入:n = 3, k = 27
输出:"aay"
解释:a=1,a=1,y=25,1+1+25=27,且是字典序最小的组合。
示例 2:
输入:n = 5, k = 73
输出:"aaszz"
解释:a=1, a=1, s=19, z=26, z=26,总和为 1+1+19+26+26=73,且前两个 'a' 保证了字典序最小。
🧠 解题分析
解题目标:
构造一个长度为 n
的字符串,使得总数值为 k
,并且满足字典序最小。
分析要点:
- 字典序最小:意味着我们希望字符尽量靠近
'a'
(最小的字符)出现在靠前位置。 - 总数值为 k:我们需要选择合适的字符组合,使得所有字符的数值之和为 k。
- 构造字符串:从左到右,尽量放
'a'
,直到无法再满足数值要求,再从右往左替换成更大的字符(比如'z'
、'y'
)来补足差值。
这就引出了我们将要使用的算法策略 —— 贪心算法。
🛠️ 解题方法:贪心算法 + 逆序构造
解法思路:
- 初始化字符串为
n
个'a'
,即全是最小的字符,数值为n
。 - 现在我们需要将总数值从
n
提升到k
,也就是需要补足k - n
。 - 从字符串末尾开始,每次尽量把
'a'
替换成尽可能大的字符(最多替换成'z'
,即加 25)。 - 重复此过程,直到补足全部差值。
Python 代码实现:
class Solution:
def getSmallestString(self, n: int, k: int) -> str:
res = ['a'] * n
k -= n # 每个 'a' 的值是 1,先减去这些最小值
i = n - 1 # 从最后一位开始修改
while k > 0:
add = min(25, k) # 最多能加到 'z'(比 'a' 多 25)
res[i] = chr(ord('a') + add)
k -= add
i -= 1
return ''.join(res)
📊 时间与空间复杂度分析
项目 | 复杂度 |
时间复杂度 |
|
空间复杂度 |
|
- 最多遍历一次长度为
n
的字符串。 - 使用了一个长度为
n
的列表存储中间结果。
🔄 方法比较与优化
方法 | 描述 | 优点 | 缺点 |
贪心算法(本方法) | 从后往前填最大值,保证字典序最小 | 简洁、高效、思路清晰 | 需要理清字典序与数值的矛盾点 |
穷举搜索 | 枚举所有可能组合并选出最小的 | 思维简单 | 性能极差,无法通过中大数据规模 |
动态规划 | 构建状态转移解最优 | 可以用于变种题 | 对本题来说是过度设计 |
🔎 特殊情况说明
k = n
:字符串全为'a'
,最小字典序。k = 26 * n
:字符串全为'z'
,但不是最小字典序。n = 1
,k = 26
:唯一可能是'z'
。
📈 延伸思考
- 如果题目要求构造字典序最大的字符串,只需从前往后尽量放
'z'
。 - 如果允许部分大写或数字字符,思路会完全不同。
- 如果要找所有满足条件的字符串,则需回溯或 BFS。
✅ 总结
这道题展示了如何在构造类问题中平衡 最小字典序 和 数值限制,是典型的“局部最优 -> 全局最优”的贪心问题。只要理解了:
- 什么样的构造能最小化字典序;
- 如何按规则修改字符值来接近目标总和;