面试指南-公共字符串求值 (c++)

【题目】

  给定一个字符串str,str表示一个公式,公式里可能有整数,加减乘除符号和左右括号,返回公式计算的结果。例如,str = 48×((70-65)-43)+8×1。返回-1816。

【说明】

  1. 可以认定给定的字符串一定是正确的公式,不需要对str做公式有效性检查。

  2. 如果是负数就需要有括号括起来,比如4*(-3)。但如果负数作为公式的开头或者括号部分的开头,则可以没有括号,比如-3*4和(-3*4)都是合法的。

  3. 不需要考虑溢出问题


本题考查面试者设计程序和代码的能力。 实现方式有很多种,本书提供一种方法供读者参考,假设value方法是一个递归过程。具体解释如下:

      从左到右遍历str , 开始遍历或遇到字符'(' 时, 就进行递归过程。 当发现str遍历完。或者遇到字符 ')' 时 ,就结束递归过程。比如“”3*(4+5)+7“”一开始遍历就进入递归过程value(str, 0 ) , 在递归过程value (str, 0)中继续遍历 str , 当遇到字符 '(' 时 , 递归过程value(str, 0)又重复调用递归过程 value (str , 3 ) ,然后在 value(str, 3 )中继续遍历str,当遇到字符‘)’ 时, 递归过程value (str , 3 ) 结束 , 并向递归过程 value (str, 0 ) 返回两个结果,第一结果是value(str, 3)遍历过的公式字符子串的结果,即“”5+4“” == 9  , 第二个结果是 value (str, 3 ) 遍历到的位置,即字符‘)’的位置 == 6  。递归过程value(str , 0 ) 收到这两个结果后,既可知道交给value(str,3) 过程处理的字符串结果是多少(“”5+4“”的结果为9),又可知道自己下一步该从什么位置继续遍历(从位置6的下一个位置(即位置7)继续遍历)。  

-------------------------------------------------------------------------------------------------------------------------    

全部解析过程可看 : 程序员代码面试指南:IT名企算法与数据结构题目最优解  p276 


C++代码如下 : 

#include <iostream> 
#include <vector>
#include <deque>
#include <string> 

using namespace std; 

class Solution
{
public:
	int getVaule(string exp){
		return  Value(exp, 0)[0];
	}

	vector<int> Value(string chars, int i)
	{
		deque<string> deq; 
		int pre = 0; 
		vector<int> bra(2);
		while (i < chars.length() && chars[i] != ')')
		{
			if (chars[i] >= '0' && chars[i] <= '9')
			{
				pre = pre * 10 + chars[i++] - '0'; 
			}
			else if (chars[i] != '(')  //表示为符号 + - * /
			{
				addNum(deq, pre);   
				deq.push_back(chars.substr(i, 1));  // 将该符号加入双端队列
				i++;    //计算下一个位置 
				pre = 0; 
			}
			else   
		// 表示为 ( , 进行下一轮递归,返回两个值 : 
	   //一个是递归的结果即(...)内的计算结果 , 另一个是次轮递归 ) 所在的位置  
			{ 
				bra = Value(chars, i + 1);
				pre = bra[0];
				i = bra[1] + 1;  //计算返回上一层计算下一个位置
			}
		}

		addNum(deq, pre);   //遇到 ) 就到这 , 例(3+4 ) ,
		      //此时 队列deq中为 3 , + ,  此时4 为pre  ,需要再加一次
		return  vector<int> {getNum(deq), i }; 
	}  

	void addNum(deque<string>& deq, int num)     //相对于去掉乘法和除法重新放回队列
	{
		if (!deq.empty())
		{
			int cur = 0; 
			string top = deq.back();  
			deq.pop_back();

			if ((top == "+") || top == "-")
			{
				deq.push_back(top);
			}
			else
			{    
				cur = atoi(deq.back().c_str());
				deq.pop_back();
				num = (top == "*" ? (cur*num) : cur / num);
			}
		}

		deq.push_back(to_string(num));  //将num放入队列
	}

	int getNum(deque<string> & deq)  // 此时deq中只有+ , -  顺序计算即可 ; 
	{
		int res = 0; 
		bool add = true; 
		string cur = ""; 
		int num = 0; 
		while (!deq.empty())
		{
			cur = deq.front();
			deq.pop_front();
			
			if (cur == "+") add = true;
			else if (cur == "-") add = false; 
			else
			{
				num = atoi(cur.c_str());
				res += add ? num : (-num);
			}
		}
		return res; 
	}

};


int main()
{
	Solution a; 
	string s = "48*((70-65)-43)+8*1";
	string s1 = "3+1*4";
	cout << a.getVaule(s1) << endl;
	system("pause");
	return 0; 
}




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值