题目描述:
给定一个仅包含数字 0-9 的字符串和一个目标值,在数字之间添加二元运算符(不是一元)+、- 或 * ,返回所有能够得到目标值的表达式。
示例 1:
输入: num = “123”, target = 6
输出: [“1+2+3”, “123”]
示例 2:
输入: num = “232”, target = 8
输出: [“23+2", "2+32”]
示例 3:
输入: num = “105”, target = 5
输出: [“1*0+5”,“10-5”]
示例 4:
输入: num = “00”, target = 0
输出: [“0+0”, “0-0”, “0*0”]
示例 5:
输入: num = “3456237490”, target = 9191
输出: []
方法1:
主要思路:
(1)使用回溯;
(2)将字符串逐渐的分割成各种的不同的长度子串,配以三种符号,生成对应的字符串,并在生成的过程中,计算各个情形下的数值,当到达字符串的末尾时,且计算的数值和给定的目标值一致时,将生成的当前的字符串存入到结果中;
(3)对于每种可能的字符串和对应的符号的选择,需要随后复原原来的字符串;
(4)在添加符号时,考虑到乘号的优先级较高,当出现乘号时,需要将乘号的值进行对应的更新,故需要保存上一个值的大小;
(5)在处理子字符串生成的数字时,考虑到数字的有效性,故当数字第一次出现为0后,需要直接返回,后面的以0作为第一位数字的组成都是无效的;
class Solution {
public:
//回溯
void backtrace(string&num,const int& target,vector<string>& res,string& path,int index,long long val,long long mult){
if(index==num.size()){//终止条件
if(val==target){//生成了符合要求的字符串
res.push_back(path);
}
return;
}
int len=path.size();//原来的字符串的长度,便于后面的复原字符串
for(int i=index;i<num.size();++i){//当前索引为起始位置,生成各种可能长度的子字符串作为对应的可能的数字
string str_val=num.substr(index,i-index+1);//当前的子字符串
long long cur_num=stol(str_val);//子字符串对应的数字
if(index==0){//起始索引为0,说明是第一个数字,故不需要符号,单独处理
path+=str_val;
backtrace(num,target,res,path,i+1,cur_num,cur_num);//更新索引,当前已经计算出来的值,及上一个值
path.resize(len);//复原字符串
}
else {
path+="+"+str_val;//加号的情形
backtrace(num,target,res,path,i+1,val+cur_num,cur_num);//更新索引,当前计算出来的值,及上一个值
path.resize(len);//复原
path+="-"+str_val;//减号的情形
backtrace(num,target,res,path,i+1,val-cur_num,-cur_num);
path.resize(len);
path+="*"+str_val;//乘号的情形,稍微复杂,因为考虑到优先级,需要重新计算值
//更新计算的值的方式和上述不同,需要先复原,再处理乘号的结果,并且上一个值的保存也是乘积的结果
backtrace(num,target,res,path,i+1,val-mult+mult*cur_num,mult*cur_num);
path.resize(len);//复原
}
if(cur_num==0){//避免出现以0作为第一位的多位的数字,此种情形是无效的,如012这种
return;
}
}
}
vector<string> addOperators(string num, int target) {
vector<string> res;//存储结果
string path="";//存储中间生成的结果
backtrace(num,target,res,path,0,0,1);
return res;
}
};