精选算法题(1)——枚举符合要求的算术表达式(DFS、回溯法)
作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
题目描述:
约定按照自然优先级,并且不使用括号,在数字'0'~'9'之间加入加号'+'或乘号'*’,构成合法的算术表达式。
对于任一给定的整数S,枚举出所有值为S的上述类型表达式。
示例:
解题思路:
本题适合用回溯法和深度优先遍历DFS解决。具体思路如下:
- 首先,罗列出所有符合要求的数字,放置在Inum容器中,比如123、12、234等等,前提是要小于整数S;
- 定义辅助函数——Calculation,使其读入一个string类型的算术表达式,比如1+3+5+6*7,能返回结果;
- 定义辅助函数——findnum,用来寻找下个符合要求的数所在的位置,比如1+2+3,后面可以放置4,也可以放置45,也可以放置456,;
- 求解函数DFS:DFS用flag来标记要用乘法还是加法,从Inum中挨个读取,因为0和9一定是单数,所以第一个读取的应该是0,拿到0后存放在str中,str用来标记当前已经有多少个数字在表达式中了,比如01234,那接下来就要找5开头的数字;字符串s用来存放表达式;开始深度优先遍历,id是当前位置,从id+1进入循环,用Calculation判断当前表达式结果是否大于S,好处是可以使遍历过程快速收敛,达到提速目的;若当前表达式符合要求,用findnum函数寻找Inum中符合要求的数字并存储其下标,基于该下标继续调用DFS,进入递归,一层层下去相当于深入到最里面的节点,即深度优先;当DFS执行到最后一个数9,用Calculation计算是否等于S,存储符合要求的表达式,返回上级节点;回归上级节点后,别忘了将str和s重置,比如1+2+3+4不合格了,那就继续执行1+2+3+45,s存放的应该是1+2+3+;当DFS执行完,结果就全出来了,因为每次运算到9后,后面还跟了一次加法和一次乘法,即9+和9*,这样就导致每次结果都存放了两次,因而输出result的时候需要间隔输出。
测试代码:
#include <iostream>
#include <string>
#include <vector>
#include <time.h>using namespace std;vector<int> num = { 0,1,2,3,4,5,6,7,8,9 };
vector<string> result;
int number;// 计算string表示的算术表达式
int Calculation(string& exp, int start, int end)
{int am = 0, md = 0;// 标记最后出现的加减乘除号位置(不在括号内)for (int i = start; i < end; ++i){if (exp[i] == '+')am = i;if (exp[i] == '*')md = i;}// 若有加减号,则将符号前面的内容和后面的内容相加或减if (am > start) {return Calculation(exp, start, am) + Calculation(exp, am + 1, end);}// 若有乘除号,则将符号前面的内容和后面的内容相乘或者除else if (md > start){return Calculation(exp, start, md) * Calculation(exp, md + 1, end); }// 若没有加减乘除,也没有内置括号,说明这部分内容是数字elsereturn stoi(exp.substr(start, end - start));
}// 寻找下个数在Inum中可能出现的位置
bool findnum(string str,vector<int> &Inum,int &id)
{// fin是最后一个字符char fin = str[str.size() - 1];// 确定下个数的位置for (int i = id; i < Inum.size(); ++i){string num = to_string(Inum[i]);if (num[0] == fin+1){id = i;return true;}// 最后一个数字如果是9,说明结束了,不用再计算了else if(fin=='9'){return false;}}return false;
}// 回溯法求解
bool DFS(string &str, vector<int>&Inum, int id,string s,bool flag)
{str += to_string(Inum[id]);if (flag){s += to_string(Inum[id]) + "+";}else {s += to_string(Inum[id]) + "*";}string tstr = str;string ts = s;// 深度优先遍历for (int i = id + 1; i < Inum.size(); ++i){// 若某个节点已经大于number,则直接跳过,使计算过程收敛,达到提速目的if (Calculation(s, 0, int(s.size() - 1)) < number){if (findnum(str, Inum, i)){DFS(str, Inum, i, s, true);DFS(str, Inum, i, s, false);}elsebreak;// 回归当前节点str = tstr;s = ts;}}// 若有结果且有9,说明算术表达式合理且成立if (Calculation(s,0,int(s.size() - 1))==number&& str.find('9')!= string::npos){result.push_back(s.substr(0,s.size()-1));return true;}return false;
}int main()
{while (cin >> number){// Inum存放所有可能出现的数字vector<int> Inum = { 0 };for (int i = 1; i < 10; ++i){int temp = num[i];Inum.push_back(temp);int k = 10;for (int j = i + 1; j < 10; ++j){temp = temp * 10 + num[j];if (temp > number){break;}Inum.push_back(temp);}}string snum;string s;// 计算clock_t start, end;start = clock();DFS(snum, Inum, 0, s, true);DFS(snum, Inum, 0, s, false);end = clock();cout << "time:" << (end - start) / CLOCKS_PER_SEC << endl;// 输出结果if (result.size() != 0){for (auto i = 0; i < result.size(); i=i+2){cout << result[i] << endl;}}else {cout << "no result!" << endl;}result.clear();}
}
测试结果:
如果代码有什么需要改进的或者有什么bug,欢迎评论留言,我会及时更正以免误导他人~
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!
精选算法题(1)——枚举符合要求的算术表达式(DFS、回溯法)相关推荐
- 精选算法题(3)——奇偶数据分离
作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半 ...
- 【算法题】解数独-用深度优先搜索(DFS)算法解数独
描述 输入一个数独棋盘,用0代表待填的空格 输出数独的一个解 示例 输入: 0 9 2 4 8 1 7 6 3 4 1 3 7 6 2 9 8 5 8 6 7 3 5 9 4 1 2 6 2 4 1 ...
- python【力扣LeetCode算法题库】999-车的可用捕获量(DFS)
车的可用捕获量 在一个 8 x 8 的棋盘上,有一个白色车(rook).也可能有空方块,白色的象(bishop)和黑色的卒(pawn).它们分别以字符 "R",".&qu ...
- leetcode算法题--全排列
原题链接:https://leetcode-cn.com/problems/permutations/ dfs+回溯 vector<vector<int>> permute(v ...
- 【算法思想:回溯法】回溯算法入门级详解
回溯法是一种非常重要的算法思想,在大厂面试中频繁出现,所以做了一个笔记,记录了一下. 回溯算法与深度优先遍历 以下是维基百科中「回溯算法」和「深度优先遍历」的定义. 回溯法 采用试错的思想,它尝试分步 ...
- c语言 用回溯算法解决01背包问题,回溯法解决01背包问题
<回溯法解决01背包问题>由会员分享,可在线阅读,更多相关<回溯法解决01背包问题(21页珍藏版)>请在人人文库网上搜索. 1.回溯法解决01背包问题,回溯法解决01背包问题, ...
- 程序员面试题精选算法58题加答案
这篇文章总结的非常好,以防以后找不到,在此转载. 程序员面试题精选(01)-把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点 ...
- 题海精华——算法题精选
前言 做了一周的算法题,在原有的算法基础上进行一些深化的题目.主要是将一些做过比较好的题的思路,并且一边做,一边也修改了一些之前发的文档优化解题方式. 类似于错题重错,一错再错,死不悔改,至死方休的记 ...
- 枚举法C语言三个马驮东西,【MagO第三期】经典枚举算法题:百钱买百鸡
原标题:[MagO第三期]经典枚举算法题:百钱买百鸡 01 历史故事 张邱建提出的百钱买百鸡问题: 山东临清的数学家--张邱建,约公元5世纪著名的大数学家.他将毕生的精力投入到算学研究之中,为数学的不 ...
最新文章
- GMF Labels
- NOIP 2018 普及组 解题报告
- C++学习笔记-----std::pair作为unordered_map的key
- os.walk() 遍历目录下的文件夹和文件
- JAVA多线程之先行发生原则
- 基于Zookeeper使用ZkClient实现分布式锁
- 剑指offer——面试题63:二叉搜索树的第k个结点
- ElasticSearch集群迁移和升级总结
- 一个服务调用另一个服务的步骤
- fork和vfork,exec
- iPhone 12面容ID解锁设置
- 一种用FFmpeg直接录屏并直播的方法
- 最小二乘法原理-线性回归
- 证券分析软件测试面试题,光大证券面试经验
- 四大步骤,彻底关闭Win10自动更新
- WebUploader 上传 php 怎么回去返回的图片路径
- 雷军:《我十年的程序员生涯》系列之二:我赚的第一桶金
- elementUI表格合并行数据
- l oracle红酒,2009 Miner Family Vineyards Oracle Red, Napa Valley, USA
- PS2019计算机丢失,小编教您ps2019中如何调出历史记录