[Divide and Conquer]241. Different Ways to Add Parentheses

题目:

题目分析:

1、根据题目要求,函数的输入为一个只涉及"+"、"-"、"×"三种运算的字符串。需要根据输入计算出所有可能计算顺序所对应的结果,并返回包含所有答案的Vector(升序)。

2、问题一:怎么才能算出所有可能的顺序呢?

很明显如果按照排列组合的方式依次添加括号,再利用栈的计算方法得出结果,涉及的代码量巨大且容易出错和遗漏。这里考虑用分治(递归)的方法解决;

假设一个字符串S(至少包含一个计算符号)所对应的答案容器为V,那么以S中任取的一个计算符C(假设是×)为分割点将S分割为L和R两部分,容器V的一部分v就可以理解为L和R两部分分别对应的答案容器VL和VR通过运算符“×”交叉相乘得到的答案集合(也就是VL和VR的内积)。而V正是由所有可能的运算符分割点二分得到的所有v的并集。由此建立起分治的算法基础。

3、问题二:递归结束的条件和处理方法?

根据问题一中提到的分治的算法,每个S的答案容器都由其所有二分子串L和R的答案容器得到,那么由此递归到最后,当L或R不可分割(即不含运算符的数字串)时,此时返回由字符串所对应的数字的容器即可。不需要再继续分割。

4、问题三:如何判断是否递归结束?结束时数字字符串如何转化为数字?

首先计算式中符号为1位,但数字不一定只是一位,因此数字长度和字符所处位置是不可掌控的。所以这里所采用的解决办法是在每次递归循环寻找字符串中对应运算符时,加入布尔变量(bool check = 0)检验是否检测到有运算符(有则check = 1)。如果循环结束时若check = 0,那么此字符串位数字串。确定为数字串后,采用以下方法转化为整数并放入返回的答案容器中。

 

if(check == 0){
			int num;
			stringstream ss(input);
			ss>>num;
			res.push_back(num);
	}

 

 

 

5、问题四:如何构造符号对应的计算函数?

这里也可以重载操作符。不过本次使用函数进行处理(加减乘分别对应add( )、sub( ) 和 mul( ) )。函数传入对象为L和R对应的答案容器VL和VR,然后进行二重循环求出所有可能的答案并放到新的答案容器中,循环结束后返回对应的容器。下方列出mul()对应的代码为例:

 

vector<int> mul(vector<int> L, vector<int> R){
	vector<int> res;
	for(int i = 0; i < L.size(); i++)
		for(int j = 0; j < R.size(); j++){
			res.push_back(L[i] * R[j]);
		}
	return res;
}

 

 

 

 

 

代码完成:

 

#include<iostream>
#include<string>
#include<vector>
#include<cstdlib>
#include<sstream>
#include<algorithm>
using namespace std;

vector<int> addV(vector<int> res, vector<int> v){
	for(int i = 0; i < v.size(); i++){
		res.push_back(v[i]);
	}
	return res;
}

vector<int> mul(vector<int> L, vector<int> R){
	vector<int> res;
	for(int i = 0; i < L.size(); i++)
		for(int j = 0; j < R.size(); j++){
			res.push_back(L[i] * R[j]);
		}
	return res;
}
vector<int> add(vector<int> L, vector<int> R){
	vector<int> res;
	for(int i = 0; i < L.size(); i++)
		for(int j = 0; j < R.size(); j++){
			res.push_back(L[i] + R[j]);
		}
	return res;
}
vector<int> sub(vector<int> L, vector<int> R){
	vector<int> res;
	for(int i = 0; i < L.size(); i++)
		for(int j = 0; j < R.size(); j++){
			res.push_back(L[i] - R[j]);
		}
	return res;
}

vector<int> Cal(const string input){
	int size = input.size();
	vector<int> res;
	bool check = 0;
	for(int i = 1; i < size; i++){
		string L = input.substr(0, i);
		//cout << "string L is: " << L << " ";
		string R = input.substr(i + 1, size - i);
		//cout << "string R is: " << R << " ";
		//cout << "The " << i << "'s index is: " << input[i] << endl;
		if(input[i] == '+'){
			res =  addV(res, add(Cal(L), Cal(R)));
			check = 1;
		}
		if(input[i] == '-'){
			res =  addV(res, sub(Cal(L), Cal(R)));
			check = 1;
		}
		if(input[i] == '*'){
			res =  addV(res, mul(Cal(L), Cal(R))); 
			check = 1;
		}
	}
	if(check == 0){
			int num;
			stringstream ss(input);
			ss>>num;
			res.push_back(num);
	}
	return res;
}

class Solution {
public:
    vector<int> diffWaysToCompute(string input) {
    	vector<int> Res = Cal(input);
    	sort(Res.begin(),Res.end());
        return Res;
    }
};

 

 

 

 

思考与完善:

1、计算的过程中可能会出现重复答案,题中并未指出是否需要合并重复的答案;

2、题中样例输出为升序,但题干中并未作此要求,实际上在提交时是有要求的;

3、有些代码的实现并不是特别精简,也不是很直观,导致debug了很长一段时间,错误也不易被发现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值