1. 算法题解析:第43题与第44题的核心思路
这两道算法题在编程面试和算法训练中具有典型性,通常涉及数组操作或动态规划等常见考点。我们先从第43题开始拆解。
1.1 第43题:字符串相乘
这道题要求实现两个用字符串表示的非负整数的乘法运算,并返回乘积的字符串表示。看似简单,但需要考虑以下几个关键点:
- 数字可能非常大,超出普通整数类型的表示范围
- 需要模拟手工乘法的竖式运算过程
- 要正确处理进位和零值的情况
核心算法步骤如下:
- 初始化一个足够长的结果数组,长度为两个输入字符串长度之和
- 从右向左遍历两个字符串的每一位
- 计算当前位的乘积并加上之前的进位
- 更新当前位的结果和新的进位
- 处理最后的进位
- 去除前导零并转换为字符串
python复制def multiply(num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0"
m, n = len(num1), len(num2)
res = [0] * (m + n)
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
mul = (ord(num1[i]) - ord('0')) * (ord(num2[j]) - ord('0'))
p1, p2 = i + j, i + j + 1
total = mul + res[p2]
res[p2] = total % 10
res[p1] += total // 10
# 去除前导零
idx = 0
while idx < len(res) and res[idx] == 0:
idx += 1
return ''.join(map(str, res[idx:]))
注意:在实际面试中,面试官可能会要求解释为什么结果数组的长度设为m+n。这是因为两个长度分别为m和n的数相乘,结果的长度不会超过m+n。
1.2 第44题:通配符匹配
这道题要求实现一个支持'?'和''的通配符匹配功能。'?'可以匹配任何单个字符,''可以匹配任意字符串(包括空字符串)。这是一个典型的动态规划问题。
解题思路:
- 定义dp[i][j]表示字符串s的前i个字符和模式p的前j个字符是否匹配
- 初始化dp[0][0]为True(两个空字符串匹配)
- 处理模式开头有多个'*'的特殊情况
- 状态转移考虑三种情况:
- p[j-1]是普通字符:必须与s[i-1]相同且dp[i-1][j-1]为True
- p[j-1]是'?':只需dp[i-1][j-1]为True
- p[j-1]是'':可以选择使用这个''(dp[i-1][j])或不使用(dp[i][j-1])
python复制def isMatch(s: str, p: str) -> bool:
m, n = len(s), len(p)
dp = [[False] * (n + 1) for _ in range(m + 1)]
dp[0][0] = True
# 处理模式开头有多个*的情况
for j in range(1, n + 1):
if p[j-1] == '*':
dp[0][j] = dp[0][j-1]
for i in range(1, m + 1):
for j in range(1, n + 1):
if p[j-1] == '?' or s[i-1] == p[j-1]:
dp[i][j] = dp[i-1][j-1]
elif p[j-1] == '*':
dp[i][j] = dp[i-1][j] or dp[i][j-1]
return dp[m][n]
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 算法优化与边界条件处理
2.1 字符串相乘的优化空间
虽然上述解法的时间复杂度已经是O(mn),但我们可以从以下几个方面进行优化:
- 使用更高效的数组操作方式
- 提前终止不必要的计算
- 优化字符串拼接过程
优化后的版本可能如下:
python复制def multiply_optimized(num1: str, num2: str) -> str:
if num1 == "0" or num2 == "0":
return "0"
res = [0] * (len(num1) + len(num2))
for i in reversed(range(len(num1))):
for j in reversed(range(len(num2))):
res[i+j+1] += int(num1[i]) * int(num2[j])
res[i+j] += res[i+j+1] // 10
res[i+j+1] %= 10
# 跳过前导零
start = 0
while start < len(res) and res[start] == 0:
start += 1
return ''.join(map(str, res[start:]))
2.2 通配符匹配的边界情况
在实际编码中,特别需要注意以下几种边界情况:
- 输入字符串为空但模式不为空(且模式全为'*')
- 模式中有连续的''(可以简化为单个'')
- 超长字符串导致的内存问题(可能需要滚动数组优化)
对于内存优化,我们可以使用滚动数组将空间复杂度从O(mn)降到O(n):
python复制def isMatch_optimized(s: str, p: str) -> bool:
m, n = len(s), len(p)
prev = [False] * (n + 1)
prev[0] = True
for j in range(1, n + 1):
if p[j-1] == '*':
prev[j] = prev[j-1]
for i in range(1, m + 1):
curr = [False] * (n + 1)
for j in range(1, n + 1):
if p[j-1] == '?' or s[i-1] == p[j-1]:
curr[j] = prev[j-1]
elif p[j-1] == '*':
curr[j] = prev[j] or curr[j-1]
prev = curr
return prev[n]
3. 算法复杂度分析与实际应用
3.1 字符串相乘的复杂度分析
原始解法:
- 时间复杂度:O(mn),其中m和n分别是两个输入字符串的长度
- 空间复杂度:O(m+n),用于存储结果
优化后的解法:
- 时间复杂度保持不变
- 空间复杂度略有降低,主要是减少了中间变量的使用
实际应用场景:
- 大整数运算库的实现
- 加密算法中的大数运算
- 科学计算中的高精度计算
3.2 通配符匹配的复杂度分析
原始DP解法:
- 时间复杂度:O(mn)
- 空间复杂度:O(mn)
滚动数组优化后:
- 空间复杂度降为O(n)
实际应用场景:
- 文件系统的通配符搜索
- 数据库的LIKE查询实现
- 正则表达式引擎的简化版本
4. 常见错误与调试技巧
4.1 字符串相乘的常见错误
- 忘记处理输入为"0"的情况
- 进位处理不正确,特别是在最高位有进位时
- 前导零去除不彻底
- 字符到数字的转换错误(如忘记减去ord('0'))
调试建议:
- 打印中间结果数组
- 使用小例子逐步验证
- 特别注意边界情况(如乘以0、乘以1)
4.2 通配符匹配的常见错误
- 初始化不正确,特别是dp[0][j]的处理
- 状态转移方程写错,特别是'*'的处理
- 索引越界问题
- 没有考虑连续'*'可以合并的情况
调试建议:
- 画出DP表格并手动填充
- 从简单例子开始(如s="a", p="a")
- 逐步增加复杂度(加入'?',然后加入'*')
我在实际解决这些问题时发现,先写出几个典型测试用例并手动计算预期结果,再与程序输出对比,是最有效的调试方法。例如对于通配符匹配,可以准备以下测试用例:
- s="aa", p="a" → False
- s="aa", p="*" → True
- s="cb", p="?a" → False
- s="adceb", p="ab" → True
- s="acdcb", p="a*c?b" → False
对于字符串相乘,好的测试用例包括:
- "0" × "123" → "0"
- "123" × "456" → "56088"
- "999" × "999" → "998001"
- "2" × "3" → "6"
- "123456789" × "987654321" → "121932631112635269"
