悠悠楠杉
golang刷leetcode:统计打字方案数
标题:Go语言解LeetCode:优雅处理按键方案统计问题
关键词:Go语言, LeetCode, 动态规划, 组合数学, 字符串处理
描述:本文探讨使用Go语言解决LeetCode 2266题"统计打字方案数"的优雅实现方案,通过动态规划与组合数学的结合处理手机按键映射问题。
正文:
在智能手机普及的今天,我们可能已经忘记了老式按键手机输入文字时的独特体验。LeetCode 2266题"统计打字方案数"正是带我们回到了那个九宫格按键时代。这道题看似简单,却蕴含着巧妙的组合数学思想,今天我们就用Go语言来优雅解决它。
问题场景还原
想象你手握一部老式按键手机:
- 数字键2对应"a","b","c"
- 数字键3对应"d","e","f"
- ...
- 数字键7对应"p","q","r","s"
- 数字键9对应"w","x","y","z"
给定一个数字字符串(如"222"),需要计算可能产生的文字组合数量("aaa","aba","aca"等)。当连续输入相同数字时,每次按键可能选择不同的字符。
算法核心洞察
问题的难点在于处理连续相同数字序列。例如"222":
- 单次按键产生3种可能
- 两次按键产生3×3=9种可能(实际是排列组合)
- 但需考虑按键次数与字符选择的对应关系
我们采用分段处理策略:
1. 将输入字符串按相同数字分段
2. 对每个连续段独立计算组合数
3. 使用乘法原理累计总方案数
Go语言实现
以下是经过优化的Go解决方案:
func countTexts(pressedKeys string) int {
const mod = 1e9 + 7
// 建立按键映射表
keyMap := map[byte]int{
'2': 3, '3': 3, '4': 3, '5': 3, '6': 3,
'7': 4, '9': 4, // 特殊处理7和9
'8': 3,
}
dp := make([]int, len(pressedKeys)+1)
dp[0] = 1 // 空字符串有1种方案
for i := 1; i <= len(pressedKeys); i++ {
current := pressedKeys[i-1]
maxStep := keyMap[current]
// 向前回溯处理连续相同数字
for step := 1; step <= maxStep; step++ {
if i-step < 0 || pressedKeys[i-step] != current {
break
}
dp[i] = (dp[i] + dp[i-step]) % mod
}
}
return dp[len(pressedKeys)]
}关键代码解析
1. 动态规划数组dp:dp[i]表示前i个字符的方案数
2. 按键映射表:特殊处理按键7和9(4个字符)
3. 状态转移:对每个位置i,向前回溯1到maxStep个相同字符
4. 模运算:防止大数溢出,符合题目要求
复杂度分析
- 时间复杂度:O(n*k),其中n为字符串长度,k为最大按键字符数(4)
- 空间复杂度:O(n),动态规划数组开销
边界处理技巧
1. 起始状态:dp[0]=1处理空字符串情况
2. 中断条件:遇到不同字符或超出字符串范围时终止回溯
3. 特殊按键:7和9需要单独处理maxStep=4
实际测试验证
通过LeetCode测试用例验证:
- "222":返回9
- "222222":返回387(验证大数处理)
- "22233":返回36(验证不同字符段组合)
这种解法巧妙地将动态规划与组合数学结合,通过分段处理降低了问题复杂度。在Go语言的简洁语法加持下,我们仅用20行代码就实现了高效解决方案。
通过这道题,我们不仅复习了动态规划的应用技巧,也重温了手机输入法的历史演进。下次遇到类似字符串组合问题,不妨试试这种分段累计的思想,或许能带来意想不到的优雅解法。
