241. 为运算表达式设计优先级(分治、区间DP)

241. 为运算表达式设计优先级

难度中等399收藏分享切换为英文接收动态反馈

给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 *

示例 1:

输入: "2-1-1"
输出: [0, 2]
解释: 
((2-1)-1) = 0 
(2-(1-1)) = 2

示例 2:

输入: "2*3-4*5"
输出: [-34, -14, -10, -10, 10]
解释: 
(2*(3-(4*5))) = -34 
((2*3)-(4*5)) = -14 
((2*(3-4))*5) = -10 
(2*((3-4)*5)) = -10 
(((2*3)-4)*5) = 10

法一:分治(递归)

遍历expression,只要一碰到操作符就把他分成左右两段,并递归下去。递归之后也是如此。

class Solution {
    public List<Integer> diffWaysToCompute(String expression) {
        char[] cs = expression.toCharArray();
        List<Integer> res = new ArrayList<>();
        int cnt = 0;  //操作符个数
        for (int i = 0; i < cs.length; i++) {
            if (cs[i] == '+' || cs[i] == '-' || cs[i] == '*') {
                ++cnt;
                List<Integer> left = diffWaysToCompute(expression.substring(0, i));
                List<Integer> right = diffWaysToCompute(expression.substring(i + 1));
                for (Integer l : left) {
                    for (Integer r : right) {
                        if (cs[i] == '+') {
                            res.add(l + r);
                        } else if (cs[i] == '-') {
                            res.add(l - r);
                        } else {
                            res.add(l * r);
                        }
                    }
                }
            }
        }
        if(cnt == 0){
            //纯数字
            res.add(Integer.valueOf(expression));
        }
        return res;
    }
}

运行结果:
请添加图片描述

法二:区间DP

思路和分治的思路类似,都是通过操作符将表达式分成左右两边。为了方便,我就预处理了一下将所有的数字和操作符分离了。

以为涉及到三维的集合,所以还是用cpp方便些。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

//区间dp
class Solution {
public:
    vector<int> diffWaysToCompute(string expression) {
        vector<int> nums;  //数字集合
        vector<char> operations; //操作符集合
        string token = "";
        for(int i = 0;i < expression.size();++i){
            if(expression[i] >= '0' && expression[i] <= '9'){
                token += expression[i];
            }else{
                nums.push_back(atoi(token.c_str()));
                operations.push_back(expression[i]);
                token = "";
            }
        }
        nums.push_back(atoi(token.c_str()));
        int n = nums.size();    //一共多少个数字
        //声明一个三维数组(实际上是二维的,第三维存的是我们要返回的结果)
        vector<vector<vector<int>>> dp(n+1,vector<vector<int>>(n+1));
        //区间长度为1的情况下
        for(int i = 0;i < n;++i){
            dp[i][i+1] = {nums[i]};
        }
        //区间长度从2到n一次递增
        for(int size = 2;size <= n;++size){
            for(int i = 0,j = size; j <= n;++i,++j){
                for(int k = i + 1;k < n;++k){
                    char operation = operations[k-1];
                    for(auto it1 = dp[i][k].begin();it1!= dp[i][k].end();++it1){
                        for(auto it2 = dp[k][j].begin();it2 != dp[k][j].end();++it2){
                            if(operation == '+'){
                                dp[i][j].push_back(*it1 + *it2);
                            }else if(operation == '-'){
                                dp[i][j].push_back(*it1 - *it2);
                            }else{
                                dp[i][j].push_back(*it1 * *it2);
                            }
                        }
                    }
                }
            }
        }
        return dp[0][n];
    }
};

运行结果:
请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值