分治策略(Divide and Conquer)
简介(Introduction)
分治策略(Divide and Conquer)是对于一个规模为 \(n\) 的问题,若该问题可以容易地解决(比如说规模 \(n\) 较小)则直接解决,否则将其分解为 \(k\) 个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
描述(Description)
- 在分治策略中,我们递归的求解一个问题,在每层递归中应用如下三个步骤:
- 分解:将一个问题划分为若干个子问题,子问题的形式与原问题一样,不过规模更小。
- 解决:递归的求解出子问题。若子问题的规模非常小则停止递归,直接求解。
- 合并:将子问题的解合并成原问题的解
应用(Application)
- 二分搜索
- 大整数乘法
- \(Strassen\) 矩阵乘法
- 棋盘覆盖
- 归并排序
- 快速排序
- 线性时间选择
- 最接近点对问题
- 循环赛日程表
- 汉诺塔
- ...
为运算表达式设计优先级
给你一个由数字和运算符组成的字符串
expression
,按不同优先级组合数字和运算符,计算并返回所有可能组合的结果。你可以 按任意顺序 返回答案。生成的测试用例满足其对应输出值符合 32 位整数范围,不同结果的数量不超过 \(10^4\)
提示:
- \(1 \le expression.length \le 20\)
expression
由数字和算符'+'
、'-'
和'*'
组成。- 输入表达式中的所有整数值在范围 \([0, 99]\)
示例 1:
输入:expression = "2-1-1"
输出:[0,2]
解释:
((2-1)-1) = 0
(2-(1-1)) = 2
示例 2:
输入:expression = "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
-
分析:
-
对于一个算式来说,总是可以根据运算符分为两部分,接着分别计算结果并合,每一个结果都是一个数组,包含这个算式的所有可能结果,计算时将左右两部分排列组合,递归的终点是字符串是纯数字,直接返回
-
分治步骤:
- 分解:按运算符分成左右两部分,分别求解
- 解决:实现一个递归函数,输入算式,返回算式解
- 合并:根据运算符合并左右两部分的解,得出最终解
-
-
题解:
// C++ Version class Solution { public: vector<int> diffWaysToCompute(string expression) { vector<int> res; //存放结果 int len = expression.size(); for(int i = 0; i < len; i++){ char c = expression[i]; if(c == '+' || c == '-' ||c == '*'){ //找到运算符,向左进行分割 auto left = diffWaysToCompute(expression.substr(0, i)); //向右进行分割 auto right = diffWaysToCompute(expression.substr(i + 1, len - i - 1)); for(int l : left){ for(int r : right){ if(c == '+'){ res.push_back(l + r); }else if(c == '-'){ res.push_back(l - r); }else if(c == '*'){ res.push_back(l * r); } } } } } //如果res中没有数字,说明expression本身为一个数字 if(res.size() == 0){ res.push_back(stoi(expression)); } return res; } };