为运算表达式设计优先级

给你一个由数字和运算符组成的字符串 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<Integer> diffWaysToCompute(String expression) {
        List<Integer> ops = new ArrayList<Integer>();
        for (int i = 0; i < expression.length();) {
            if (!Character.isDigit(expression.charAt(i))) {
                if (expression.charAt(i) == ' ') {
                    ops.add(ADDITION);
                } else if (expression.charAt(i) == '-') {
                    ops.add(SUBTRACTION);
                } else {
                    ops.add(MULTIPLICATION);
                }
                i  ;
            } else {
                int t = 0;
                while (i < expression.length() && Character.isDigit(expression.charAt(i))) {
                    t = t * 10   expression.charAt(i) - '0';
                    i  ;
                }
                ops.add(t);
            }
        }
        List<Integer>[][] dp = new List[ops.size()][ops.size()];
        for (int i = 0; i < ops.size(); i  ) {
            for (int j = 0; j < ops.size(); j  ) {
                dp[i][j] = new ArrayList<Integer>();
            }
        }
        for (int i = 0; i < ops.size(); i  = 2) {
            dp[i][i].add(ops.get(i));
        }
        for (int i = 3; i <= ops.size(); i  ) {
            for (int j = 0; j   i <= ops.size(); j  = 2) {
                int l = j;
                int r = j   i - 1;
                for (int k = j   1; k < r; k  = 2) {
                    List<Integer> left = dp[l][k - 1];
                    List<Integer> 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算法运算表达式优先级的资料请关注Devmax其它相关文章!

Go Java算法之为运算表达式设计优先级实例的更多相关文章

  1. iOS推送通知优先级

    我已设置推送通知并正常工作,但是,有时我会遇到终端设备上的延迟交付.有没有办法我可以将推送的“优先级”键设置为10,以便立即发送推送?

  2. ios – 何时使用Semaphore而不是Dispatch Group?

    我会假设我知道如何使用DispatchGroup,为了解问题,我尝试过:结果–预期–是:为了使用信号量,我实现了:并在viewDidLoad方法中调用它.结果是:从概念上讲,dispachGroup和Semaphore都有同样的目的.老实说,我不熟悉:什么时候使用信号量,尤其是在与dispachGroup合作时–可能–处理问题.我错过了什么部分?

  3. 如何使用Xcode的自动布局调整视图大小

    解决方法在写这个问题时,我意识到了诀窍是什么:在NSPopUpButton的大小检查器中,我不得不降低内容拥抱优先级.显然,这可以控制视图“拥抱”其内容的紧密程度.因此,当拥抱优先级高于调整大小优先级时,视图将不希望增加其大小,因为这意味着其边界与其内容之间具有更多的空白空间.然后在我的特殊情况下,我也可以将两个NSPopUpButtons固定为具有相同的宽度和vo:popUpButtons将完美地调整大小,同时保持间距不变.

  4. ios – 默认的自动布局内容拥抱和内容压缩阻抗优先级值是什么?

    我正在尝试调试自动布局问题,并且知道内容拥抱和内容压缩阻力优先级的默认值将有所帮助.这些是什么?它们是否特定于特定组件?我可以使用常量来引用它们吗?

  5. ios – 为自定义创建的串行异步队列设置优先级

    如何使用GCD为自定义创建的串行异步队列设置高优先级?如果是这样,什么是替代解决方案?解决方法您的队列仍然是串行的.它只会在高优先级全局并发后台队列的一个插槽中一次执行一项任务.一旦创建,串行队列就不能以任何方式“并发”.同样,如果您创建并发队列并将其设置为以串行队列为目标,则它实际上变为串行.这一切都在manpage中有所涉及.

  6. iOS 9中UILabel中的多行文本

    我正在开发iOS项目但是当我更新到iOS9时,我在UILabels中遇到了多线问题.我正在使用Autolayout.有谁知道如何在iOS9中做到这一点?如果是这样,那么问题可能是标签内容压缩阻力优先级太低,尝试将其设置为required或1000.内容压缩阻力告诉视图引擎您的标签可以缩小的优先级.将其设置为必需会强制它不缩小.在InterfaceBuilder中,只需选择标签,点击SizeInspector(小标尺),然后将其更改为1000.或者,在代码中,等价物将是:

  7. ios – AutoLayout修改约束

    我发现Autolayout有点困难,所以任何帮助都会非常感激解决方法嗨,你可以做2套约束:>1以优先级高管理您的四视图>1以优先级低管理全屏在点击按钮时调用的方法中,将优先级设置为全屏约束,将优先级设置为四视图约束.

  8. 用Swift实现MD5算法&amp;引入第三方类库MBProgressHUD

    之前项目里面是用objc写的MD5加密算法,最近在用swift重写以前的项目,遇到了这个问题。顺带解决掉的还有如何引入第三方的类库,例如MBProgressHUD等一些特别好的控件解决的方法其实是用objc和swift混合编程的方法,利用Bridging-header文件。你可以简单的理解为在一个用swift语言开发的工程中,引入objective-c文件是需要做的一个串联文件,好比架设了一个桥,让swift中也可以调用objective-c的类库和frame等等。

  9. Swift 运算符重载

    但是现在还有另外一个Swift的特性,你应该知道并且会爱上它,它就是运算符重载。例如:我们在SwiftSpriteKitutilitylibrary代码中使用运算符重载去讲多个CGPoints对象相加,例如下面代码:1234letpt1=CGPointletpt2=CGPointletpt3=pt1+pt2letpt4=pt3*100方便吧?当一个人查看你的代码,他们希望操作符的默认行为,这时候运算符重载会使他们迷惑。幸运的是Swift让你能够定义属于你自己的自定义的运算符。

  10. Swift学习一:自定义运算符 operator

    自定义运算符仅能包含这些字符:运算符位置:运算符其他配置范例

随机推荐

  1. 基于EJB技术的商务预订系统的开发

    用EJB结构开发的应用程序是可伸缩的、事务型的、多用户安全的。总的来说,EJB是一个组件事务监控的标准服务器端的组件模型。基于EJB技术的系统结构模型EJB结构是一个服务端组件结构,是一个层次性结构,其结构模型如图1所示。图2:商务预订系统的构架EntityBean是为了现实世界的对象建造的模型,这些对象通常是数据库的一些持久记录。

  2. Java利用POI实现导入导出Excel表格

    这篇文章主要为大家详细介绍了Java利用POI实现导入导出Excel表格,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  3. Mybatis分页插件PageHelper手写实现示例

    这篇文章主要为大家介绍了Mybatis分页插件PageHelper手写实现示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  4. (jsp/html)网页上嵌入播放器(常用播放器代码整理)

    网页上嵌入播放器,只要在HTML上添加以上代码就OK了,下面整理了一些常用的播放器代码,总有一款适合你,感兴趣的朋友可以参考下哈,希望对你有所帮助

  5. Java 阻塞队列BlockingQueue详解

    本文详细介绍了BlockingQueue家庭中的所有成员,包括他们各自的功能以及常见使用场景,通过实例代码介绍了Java 阻塞队列BlockingQueue的相关知识,需要的朋友可以参考下

  6. Java异常Exception详细讲解

    异常就是不正常,比如当我们身体出现了异常我们会根据身体情况选择喝开水、吃药、看病、等 异常处理方法。 java异常处理机制是我们java语言使用异常处理机制为程序提供了错误处理的能力,程序出现的错误,程序可以安全的退出,以保证程序正常的运行等

  7. Java Bean 作用域及它的几种类型介绍

    这篇文章主要介绍了Java Bean作用域及它的几种类型介绍,Spring框架作为一个管理Bean的IoC容器,那么Bean自然是Spring中的重要资源了,那Bean的作用域又是什么,接下来我们一起进入文章详细学习吧

  8. 面试突击之跨域问题的解决方案详解

    跨域问题本质是浏览器的一种保护机制,它的初衷是为了保证用户的安全,防止恶意网站窃取数据。那怎么解决这个问题呢?接下来我们一起来看

  9. Mybatis-Plus接口BaseMapper与Services使用详解

    这篇文章主要为大家介绍了Mybatis-Plus接口BaseMapper与Services使用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  10. mybatis-plus雪花算法增强idworker的实现

    今天聊聊在mybatis-plus中引入分布式ID生成框架idworker,进一步增强实现生成分布式唯一ID,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

返回
顶部