作者:翟天保Steven
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

题目描述:

约定按照自然优先级,并且不使用括号,在数字'0'~'9'之间加入加号'+'或乘号'*’,构成合法的算术表达式。

对于任一给定的整数S,枚举出所有值为S的上述类型表达式。

示例:

图1 示例

解题思路:

本题适合用回溯法和深度优先遍历DFS解决。具体思路如下:

  1. 首先,罗列出所有符合要求的数字,放置在Inum容器中,比如123、12、234等等,前提是要小于整数S;
  2. 定义辅助函数——Calculation,使其读入一个string类型的算术表达式,比如1+3+5+6*7,能返回结果;
  3. 定义辅助函数——findnum,用来寻找下个符合要求的数所在的位置,比如1+2+3,后面可以放置4,也可以放置45,也可以放置456,;
  4. 求解函数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();}
}

测试结果:

图2 结果

如果代码有什么需要改进的或者有什么bug,欢迎评论留言,我会及时更正以免误导他人~

如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

精选算法题(1)——枚举符合要求的算术表达式(DFS、回溯法)相关推荐

  1. 精选算法题(3)——奇偶数据分离

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半 ...

  2. 【算法题】解数独-用深度优先搜索(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 ...

  3. python【力扣LeetCode算法题库】999-车的可用捕获量(DFS)

    车的可用捕获量 在一个 8 x 8 的棋盘上,有一个白色车(rook).也可能有空方块,白色的象(bishop)和黑色的卒(pawn).它们分别以字符 "R",".&qu ...

  4. leetcode算法题--全排列

    原题链接:https://leetcode-cn.com/problems/permutations/ dfs+回溯 vector<vector<int>> permute(v ...

  5. 【算法思想:回溯法】回溯算法入门级详解

    回溯法是一种非常重要的算法思想,在大厂面试中频繁出现,所以做了一个笔记,记录了一下. 回溯算法与深度优先遍历 以下是维基百科中「回溯算法」和「深度优先遍历」的定义. 回溯法 采用试错的思想,它尝试分步 ...

  6. c语言 用回溯算法解决01背包问题,回溯法解决01背包问题

    <回溯法解决01背包问题>由会员分享,可在线阅读,更多相关<回溯法解决01背包问题(21页珍藏版)>请在人人文库网上搜索. 1.回溯法解决01背包问题,回溯法解决01背包问题, ...

  7. 程序员面试题精选算法58题加答案

    这篇文章总结的非常好,以防以后找不到,在此转载. 程序员面试题精选(01)-把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点 ...

  8. 题海精华——算法题精选

    前言 做了一周的算法题,在原有的算法基础上进行一些深化的题目.主要是将一些做过比较好的题的思路,并且一边做,一边也修改了一些之前发的文档优化解题方式. 类似于错题重错,一错再错,死不悔改,至死方休的记 ...

  9. 枚举法C语言三个马驮东西,【MagO第三期】经典枚举算法题:百钱买百鸡

    原标题:[MagO第三期]经典枚举算法题:百钱买百鸡 01 历史故事 张邱建提出的百钱买百鸡问题: 山东临清的数学家--张邱建,约公元5世纪著名的大数学家.他将毕生的精力投入到算学研究之中,为数学的不 ...

最新文章

  1. GMF Labels
  2. NOIP 2018 普及组 解题报告
  3. C++学习笔记-----std::pair作为unordered_map的key
  4. os.walk() 遍历目录下的文件夹和文件
  5. JAVA多线程之先行发生原则
  6. 基于Zookeeper使用ZkClient实现分布式锁
  7. 剑指offer——面试题63:二叉搜索树的第k个结点
  8. ElasticSearch集群迁移和升级总结
  9. 一个服务调用另一个服务的步骤
  10. fork和vfork,exec
  11. iPhone 12面容ID解锁设置
  12. 一种用FFmpeg直接录屏并直播的方法
  13. 最小二乘法原理-线性回归
  14. 证券分析软件测试面试题,光大证券面试经验
  15. 四大步骤,彻底关闭Win10自动更新
  16. WebUploader 上传 php 怎么回去返回的图片路径
  17. 雷军:《我十年的程序员生涯》系列之二:我赚的第一桶金
  18. elementUI表格合并行数据
  19. l oracle红酒,2009 Miner Family Vineyards Oracle Red, Napa Valley, USA
  20. PS2019计算机丢失,小编教您ps2019中如何调出历史记录

热门文章

  1. iOS 用runtime封装字典转模型
  2. FreeRTOS(五)——heap文件解析
  3. MySql 手动执行主从备份
  4. iOS 图形处理 翻译
  5. 新书《Ext JS 4.2 实战》终于出炉了
  6. JavaThread学习
  7. code vs 集成tfs_10大Python集成开发环境和代码编辑器
  8. 【写作技巧】毕业论文如何写目录?
  9. html 块级注释,HTML blockquote 标签 | 教程 | codingbefore
  10. 微信语音麦克风静音_智能语音专题(二):语音信号处理