算法分析与设计课程03——Expression Add Operators(Hard)

    xiaoxiao2021-03-25  66

    一、题目描述(中文)

    ————————————原题链接 给定一个由0~9组成的字符串例如“123”,和一个目标值6要求只使用“+”“-”“*”这三个运算操作符,将“123”变成6,如下更多例子

    "123", 6 -> ["1+2+3", "1*2*3"] "232", 8 -> ["2*3+2", "2+3*2"] "105", 5 -> ["1*0+5","10-5"] "00", 0 -> ["0+0", "0-0", "0*0"] "3456237490", 9191 -> []

    二、解题思路

    1、简单例子分析

    这个题其实采用穷举法将该字符串能够表示的方案和目标值一一对比,找出符合目标值的方案集合,但关键的问题是如何穷举,以”105”为分析例子

    我们首先取出字符串中的“1”然后再取出其后的“0”,执行加减乘: 1+0=1 ① 1-0=1 ② 1*0=0 ③

    因为要用到“105”的所有数字,所以我们得到将上面执行加减乘的结果,再和剩余的“5”作用

    执行操作“+”“-”“*”①和51+5=61-5=-41*5=5②和51+5=61-5=-41*5=5③和50+5=50-5=-50*5=0

    注意这里为什么没有①和②的结果即:(1+0)5和(1-0)*5出现,因为题目没有提供括号()的运算,所以根据运算优先级,上面两个结果就变成1+0*5=1和1-0*5=1,不能得到目标值,所以我们得到一个重要的条件——没有括号改变优先级

    所以根据上面我们得到一个方案1:1*0+5

    除了取出一个字符外,我们也可以去除两个或者更多字符,我们去除“10”这个字符,还剩下“5”这个字符,很简单的就能得到一个方案2:10-5,这里能得到另外一个条件——可以取出任意多个字符

    如果取出“105”自然不得5,所以我们就只能得到两个方案。

    2、规律总结

    根据上面两个条件:没有括号改变优先级和可以取出任意多个字符,和上面的解题思路,我们能得到以下的递归步骤:

    每次划分将字符串S分为S1和S2两个部分

    ①规定原始值:在没有什么初始条件下,划分S使得S1具有1个字符,得到初始的中间值,例如“105”中得到1,之后再执行这步划分的时候,使得S1具有2个、3个…直至字符串的长度为止(如”105”长度为3,所以S1到3就停止了)

    ②使用得到的S1和之前的结果执行运算,然后再讲S2当做子字符串作为S再次划分

    (⊙o⊙)…额,直接看代码会更好一点,反正记得那两个条件就行了

    三、代码部分(以下代码可以直接在leetcode上通过,当然你也可以在dev c++ 里测试对比你的代码)

    注意:用了long long 类型的变量是因为 leetcode 中有个测试是使用字符串“2147483648”这个东西,不论你用整形int还是长整型long来存都会超出取值范围,而直接变成数字-2147483648,所以一定要使用long long类型来存。

    相关细节在代码里面体现,重要的事情说3遍——记住那两个条件。

    #include <iostream> #include <vector> #include <cmath> using namespace std; vector<string> addOperators(string num, int target); void getResult(string num, int & target, string final_result, long long final_target, vector<string> & result, int flag, long long lastvalue); int main() { while(true) { string num = ""; int target = 0; cin >> num >> target; vector<string> result = addOperators(num, target); for(int i = 0; i < result.size(); i ++) cout << result[i] << endl; cout << "——————————" << endl; } return 0; } vector<string> addOperators(string num, int target) { vector<string> result; if(num == "") return result; int flag = num.size();//flag是得到初始条件的标志,因为我不想在取出来的第一个值的前面加上“+”号之类的东西 getResult(num, target, "", 0, result, flag, 0); return result; } void getResult(string num, int & target, string final_result, long long final_target, vector<string> & result, int flag, long long lastvalue) { int size = num.size(); if(size == 0) { if(final_target == target) result.push_back(final_result); } else { for(int i = 0; i < size; i ++) { string sub = num.substr(i + 1, size - i - 1); string current_num = num.substr(0, i + 1); long long current_value = 0; //下面那个循环是为了将字符串转化为数值 for(int i = current_num.size() - 1, j = 0; i >= 0; i --, j ++) current_value += (long long)((int)current_num[j] - 48) * (long long)pow(10, i); if(current_num.size() > 1 && current_num[0] == '0') continue; if(flag == size) { getResult(sub, target, final_result + current_num, final_target + current_value, result, flag, current_value); } else { getResult(sub, target, final_result + "+" + current_num, final_target + current_value, result, flag, current_value); getResult(sub, target, final_result + "-" + current_num, final_target - current_value, result, flag, -current_value); long long cha = final_target - lastvalue; getResult(sub, target, final_result + "*" + current_num, lastvalue * current_value + cha, result, flag, lastvalue * current_value); } } } }
    转载请注明原文地址: https://ju.6miu.com/read-34461.html

    最新回复(0)