原题目
给定一个含有数字和运算符的字符串,为表达式添加括号,改变其运算优先级以求出不同的结果。你需要给出所有可能的组合的结果。有效的运算符号包含 +, - 以及 * 。
示例 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
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/different-ways-to-add-parentheses
题目大意
给你一个运算表达式,求在不同地方打括号得到的值,括号个数任意
题目分析
分治法:
遇到运算符的时候就依次计算左边部分和右边部分
每个运算符左边部分的所有可能值,与右边的所有可能值用该运算符逐一运算,组成的所有可能值即为答案。
使用递归方法,每次以运算符分为两半,然后对运算符左边部分和右边部分分别进行递归,重复执行以上步骤,最后分的只剩数字为止。
可能不理解
举个例子:
输入: “2 * 3 - 4 * 5”
输出: [-34, -14, -10, -10, 10]
循环找到第一个运算符 *
左边 2
右边 3 - 4* 5
左边递归,只剩2,直接返回该值
右边递归,找到第一个运算符 -
左边3
右边4 * 5
左边递归,只剩3,直接返回该值
右边递归,找到第一个运算符 *
左边4
右边5
左边递归,只剩4,直接返回该值
右边递归,只剩5,直接返回该值
返回上一层,4 * 5,用该运算符对左右进行运算,得20
继续返回上一层,3 - 20,得-17,返回上一层
找到第二个运算符 *
左边3 - 4
右边5
左边递归,返回-1
右边递归,返回5
计算-1 * 5=-5 返回-5
该层运算符找完,得到两个值【-17,-5】返回该数组
将该层运算符左边的值与右边的值一一运算,
2 *(-17)=-34
2 *(-5)=-10
该运算符递归结束得到两个值【-34,-10】
继续找下一个运算符 -
左边2 * 3
右边4 * 5
左边递归,返回6
右边递归,返回20
则6-20=-14
该运算符递归结束得到一个值【-14】
继续找下一个运算符 *
左边 2 * 3 - 4
右边5
左边递归返回【2,-2】
2 * 5=10;
-2* 5=-10;
该运算符递归结束得到两个值【-10,10】
所以一共有5个值。
完整代码
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* diffWaysToCompute(char * input, int* returnSize){
int *res = (int *)malloc(sizeof(int)*10000);
int k = 0;
int len = strlen(input);
for(int i = 0;i < len; i++){
int *s1;
int *s2;
int len1 = 0;
int len2 = 0;
if(input[i] == '+' || input[i] == '-' || input[i] == '*'){
char *c1=(char *)malloc(sizeof(char)*len);
char *c2=(char *)malloc(sizeof(char)*len);
memset(c1,0,sizeof(char)*len);
memset(c2,0,sizeof(char)*len);
strncpy(c1,input,i);
strcpy(c2,input+i+1);
s1 = diffWaysToCompute(c1,&len1);
s2 = diffWaysToCompute(c2,&len2);
}
for(int j = 0; j < len1; j++){
for(int l = 0; l < len2; l++){
if(input[i] == '+'){
res[k]=s1[j]+s2[l];
}
if(input[i] == '-'){
res[k]=s1[j]-s2[l];
}
if(input[i] == '*'){
res[k]=s1[j]*s2[l];
}
k++;
}
}
}
if(k == 0){
res[0] = atoi(input);
k++;
}
*returnSize = k;
return res;
}
class Solution {
public:
vector<int> diffWaysToCompute(string input) {
vector<int>res;
for(int i=0;i<input.size();i++)//每一层找运算符
{
char s=input[i];//用s存储运算符
vector<int>s1,s2;//s1,s2存储每层返回的数据数组
if(s=='+'||s=='-'||s=='*')//遇到运算符就分别往左往右递归
{
s1=diffWaysToCompute(input.substr(0,i));
s2=diffWaysToCompute(input.substr(i+1));
}
for(auto j:s1)
for(auto k:s2)//用运算符计算左右两边的值,存入数组
{
if(s=='+')
res.push_back(j+k);
else if(s=='-')
res.push_back(j-k);
else if(s=='*')
res.push_back(j*k);
}
}
if(res.empty())//如果最后只剩数字字符串,直接将字符串转换为数字即可存入即可
{
res.push_back(stoi(input));
}
return res;//返回该层的情况
}
};
执行用时 :
8 ms, 在所有 C++ 提交中击败了86.49%的用户
内存消耗 :
13.6 MB, 在所有 C++ 提交中击败了26.90%的用户
总结
了解分治算法,灵活运用,弄懂递归回溯思想