coverPiccoverPic

Leetcode282 给表达式添加运算符

思路

Expression Add Operators,这是一道 hard 难度的题目,需要我们对给定的数字字符串num分为若干个连续子串,输出用 +、- 和 * 连起来后,等于target的表达式。这个题目解法全是暴力,没有一丝技巧。num的长度即为nn,在两个数字之间可以选择进行四种操作(不插入符号、+、- 和 * )。

如果不是会超时的话,大概直接 DFS 遍历四种操作,最后eval出结果就好了。考虑到这个问题尝试用eval来计算表达式结果超时的问题,我们需要在遍历过程中去计算表达式的结果。

下面的方法思路是在遍历过程中考虑数字如何划分,也就是说,每次加入表达式的数字是多少位,然后枚举 +、- 和 * 三种情况。

计算的话,如果是 + 或者 - 直接在先前结果上面加减即可。如果是 *,则需要把表达式最后一个单项式减去,再乘上新的数字,然后加回表达式之中。

也就是说,我们的递归函数dfs需要四个状态:exp记录已生成的表达式,index记录这次调用起始的num下标,res即已生成表达式的结果,preNum是最后一个单项式。

复杂度

时间复杂度: O(4n)O(4^n)nnnum的长度,由于每个位置之间存在四种插入决策(不插入符号、+、- 和 *),共有n1n−1个位置可以插入符号,组成表达式需要O(4n1)O(4^{n-1})的复杂度,加上计算表达式需要O(n)O(n)复杂度,时间复杂度为O(n4n1)O(n4^{n-1})…吗?根据这个题解(详见给表达式添加运算符),表达式的个数不会超过O(3n1)O(3^{n-1}),复制表达式到答案用时不超过O(n3n1)O(n3^{n-1})

空间复杂度: O(n)O(n),递归栈空间和记录表达式的遍历空间复杂度都是O(n)O(n),不考虑结果所占空间。

Code

ts
  1. function addOperators(num: string, target: number): string[] {
  2. const ans = []
  3. const exp = []
  4. const numLen = num.length
  5. const dfs = (index: number, res: number, preNum: number) => {
  6. if (index === numLen) {
  7. if (res === target) {
  8. ans.push(exp.join(''))
  9. }
  10. } else {
  11. let curNum = 0
  12. const preLength = exp.length
  13. exp.push('')
  14. const signIndex = exp.length - 1
  15. for (let j = index; j < numLen; j++) {
  16. if (j !== index && num[index] === '0') {
  17. break
  18. }
  19. curNum = curNum * 10 + (num[j] as any - 0)
  20. exp.push(num[j])
  21. if (index === 0) {
  22. dfs(j + 1, curNum, curNum)
  23. } else {
  24. exp[signIndex] = '+'
  25. dfs(j + 1, res + curNum, curNum)
  26. exp[signIndex] = '-'
  27. dfs(j + 1, res - curNum, -curNum)
  28. exp[signIndex] = '*'
  29. dfs(j + 1, res - preNum + preNum * curNum, preNum * curNum)
  30. }
  31. }
  32. exp.length = preLength
  33. }
  34. }
  35. dfs(0, 0, 0)
  36. return ans
  37. };
0 条评论未登录用户
Ctrl or + Enter 评论
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run