Go Java算法之为运算表达式设计优先级实例

这篇文章主要为大家介绍了Go Java算法之为运算表达式设计优先级实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

为运算表达式设计优先级

给你一个由数字和运算符组成的字符串 expression ,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以 按任意顺序 返回答案。

生成的测试用例满足其对应输出值符合 32 位整数范围,不同结果的数量不超过 104 。

  • 示例 1:

输入:expression = "2-1-1"

输出:[0,2]

解释:

((2-1)-1) = 0

(2-(1-1)) = 2

  • 示例 2:
  • 输入:expression = "23-45"
  • 输出:[-34,-14,-10,-10,10]

解释:

(2*(3-(4*5))) = -34

((23)-(45)) = -14

((2*(3-4))*5) = -10

(2*((3-4)*5)) = -10

(((2*3)-4)*5) = 10  

提示:

1 <= expression.length <= 20

expression 由数字和算符 '+'、'-' 和 '*' 组成。

输入表达式中的所有整数值在范围 [0, 99] 

方法一:动态规划(Java)

因为最终的答案是由一个个子问题(子表达式)的答案所构成,所以我们可以采用动态规划,将问题划分为一个个子问题来求解。

做出此题最关键的一步是要写出合理的动态规划递归式。第一想法是定义dp[i]表示前i个数计算的结果,这样定义我们很快会发现我们无法写出dp[i+1],因为它们相互包含,没有明确的界限。

比较好的递归式是定义dp[i][j]表示从第i个数开始到第j个数的表达式计算的结果,最终结果就是要求dp[0][N-1]。

首先我们将字符串分成digit、op、digit、op、digit、op、digit.....这样的序列,并且可知序列的长度是奇数个,所以子问题的最小长度为3(长度为1的digit不需要计算),也就是一个op运算需要至少三个元素(两个digit和一个op),下一个子问题的长度为当前子问题+2(加一个op和一个digit),所以我们可以从最小长度为3的子问题一步步求解最大长度的解。

class Solution { static final int ADDITION = -1; static final int SUBTRACTION = -2; static final int MULTIPLICATION = -3; public List diffWaysToCompute(String expression) { List ops = new ArrayList(); for (int i = 0; i [][] dp = new List[ops.size()][ops.size()]; for (int i = 0; i (); } } for (int i = 0; i  left = dp[l][k - 1]; List right = dp[k + 1][r]; for (int num1 : left) { for (int num2 : right) { if (ops.get(k) == ADDITION) { dp[l][r].add(num1 + num2); } else if (ops.get(k) == SUBTRACTION) { dp[l][r].add(num1 - num2); } else if (ops.get(k) == MULTIPLICATION) { dp[l][r].add(num1 * num2); } } } } } } return dp[0][ops.size() - 1]; } }; 

时间复杂度:O(2^n)

空间复杂度:O(2^n)

方法二:分治(Go)

分治:定义最后一个生效的符号位置。比如 a+b+c+d,我们定义第二个加号,为最后的计算位置,则可以得到【a+b】+【c+d】,类似这样的格式。然后此时可以发现 A=a+b 是一个表达式,B=c+d也是一个表达式,他们可以分别计算出各自的结果,然后再通过这个加号计算 A+B,每组两部分的和就对应所有可能的结果

对于一个形如 x op y(op 为运算符,x 和 y 为数) 的算式而言,它的结果组合取决于 x 和 y 的结果组合数,而 x 和 y 又可以写成形如 x op y 的算式。

因此,该问题的子问题就是 x op y 中的 x 和 y:以运算符分隔的左右两侧算式解。

分治算法三步走:

  • 分解:按运算符分成左右两部分,分别求解
  • 解决:实现一个递归函数,输入算式,返回算式解
  • 合并:根据运算符合并左右两部分的解,得出最终解
import ( "fmt" "strconv" ) func diffWaysToCompute(input string) []int { // 如果是数字,直接返回 if isDigit(input) { tmp, _ := strconv.Atoi(input) return []int{tmp} } // 空切片 var res []int // 遍历字符串 for index, c := range input { tmpC := string(c) if tmpC == "+" || tmpC == "-" || tmpC == "*" { // 如果是运算符,则计算左右两边的算式 left := diffWaysToCompute(input[:index]) right := diffWaysToCompute(input[index+1:]) for _, leftNum := range left { for _, rightNum := range right { var addNum int if tmpC == "+" { addNum = leftNum + rightNum } else if tmpC == "-" { addNum = leftNum - rightNum } else { addNum = leftNum * rightNum } res = append(res, addNum) } } } } return res } // 判断是否为全数字 func isDigit(input string) bool { _, err := strconv.Atoi(input) if err != nil { return false } return true } 

时间复杂度:O(2^n)

空间复杂度:O(2^n)

以上就是Go Java算法之为运算表达式设计优先级实例的详细内容,更多关于Go Java算法运算表达式优先级的资料请关注0133技术站其它相关文章!

以上就是Go Java算法之为运算表达式设计优先级实例的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » Java