一元一次方程的解法
找工作投简历的时候遇到这样一道题,“如何通过基础的解析字符串的方式去求解一元一次方程,而不通过工具包或者内置函数等计算?”,即输入任意一个一元一次函数(如:"((2x+1)*3+1)+(3+2x)=5x+3+(2x+1)"等等 ),当时觉得有趣,于是想好好做一下~
最开始的时候想直接从表达式下手,但是由于有括号对优先级的影响,使得考虑的情况实在是比较复杂,于是便想到分别利用两个栈对表达式求解(data栈用来存储数字{'0','1','2','3','4','5','6','7','8','9','x'},operation栈用来存储操作运算符{'+','-','*','/'},对于利用栈计算算术表达式,这篇博客有详细讲解:https://blog.csdn.net/xyh1re/article/details/81634236。而对于计算x解析解而言,为了方便计算,需要将表达式转换为[a,b]**[x0,x1].T的形式(即a表示常数项,b表示一次项),这里又要分几种情况:
(1)当操作符为{‘+’,‘-’}时,即形如(ax+b),这里经转换得到: np.array([0,a])+np.array([b,0])=np.array([b,a])
(2)当操作符为{‘*’,‘/’}时,即形如(ax+b)*c,这里经转换得到:np.array([b,a])*np.array([c,c]),注意此时的转换方式有变化(不是np.array([c,0]))。
详细的代码如下:
# 将表达式进行标准化,即[a,b]*(x0,x1).T的形式
# 利用两个栈实现表达式的运算
# operation 保存运算符
# data 保存数字
# 遍历表达式,若为数字则直接入栈data,若为符号分几种情况入栈opration:
# (1)栈为空
# (2)栈顶为左括号
# (3)该符号为左括号
# (4)该符号优先级高于栈顶符号
# 若符号为右括号,则operation输出栈顶符号,从data输出两个数运算再入栈data,
# 直到栈顶为左括号,然后左括号出栈,若符号优先级低于栈顶元素,则重复计算步骤,
# 直到栈为空或栈顶为左括号。
import numpy as np
number={'0','1','2','3','4','5','6','7','8','9','x'}
def data_process1(string): #如:5x
if not isinstance(string,str):
return string
a=0
b=0
index=-1
for i in range(len(string)):
if string[i]=="x":
index=i
if index==-1: # 5
a=float(string)
b=0.0
elif index==0: # x
a=0.0
b=1.0
elif index==1: # -x,2x
if string[0]=="-":
a=0.0
b=-1.0
else:
a=0.0
b=float(string[0])
else: # 5x
a=0.0
b=float(string[:index])
return np.array([a,b])
def data_process2(string): #如:5x
if not isinstance(string,str):
return string
a=0
b=0
index=-1
for i in range(len(string)):
if string[i]=="x":
index=i
if index==-1: # 5
a=float(string)
b=float(string)
elif index==0: # x
a=0.0
b=1.0
elif index==1: # -x,2x
if string[0]=="-":
a=0.0
b=-1.0
else:
a=0.0
b=float(string[0])
else: # 5x
a=0.0
b=float(string[:index])
return np.array([a,b])
def num_operation(num1,num2,op):
if op=="+":
return data_process1(num1)+data_process1(num2)
if op=="-":
return data_process1(num1)-data_process1(num2)
if op=="*":
return data_process2(num1)*data_process2(num2)
if op=="/":
return data_process2(num1)/data_process2(num2)
def caculate(data,operation):
op=operation.pop()
num2=data.pop()
num1=data.pop()
data.APPend(num_operation(num1,num2,op))
def function(s):
data=[]
operation=[]
i=0
while i<len(s):
if s[i] in number: #数字直接入栈data
start=i
while i+1 <len(s) and s[i+1] in number:
i+=1
data.append(s[start:i+1])
#栈为空或者栈顶为左括号,入栈operation
elif not operation or operation[-1]=="(":
operation.append(s[i])
#该符号为左括号或优先级高于栈顶元素,入栈operation
elif s[i]=="(" or (s[i] in {"*","/"} and operation[-1] in {"+","-"}):
operation.append(s[i])
#该符号为右括号,则operation出栈,data出栈进行计算
elif s[i]==")":
while operation[-1]!="(":
caculate(data,operation)
operation.pop()
#该符号优先级不如栈顶高时,operation出栈,data出栈进行计算,直到栈为空或栈顶为左括号
else:
while operation and (operation[-1] in {"*","/"} and s[i] in {"+","-"}):
if operation[-1]=="(":
break
caculate(data,operation)
operation.append(s[i])
i+=1
while operation:
caculate(data,operation)
answer=data.pop()
if isinstance(answer,str):
return data_process1(answer)
return answer
if __name__ == '__main__':
s=input() # 输入合法的表达式,如 1+((2x+3)*2+1)+2x=5x 请勿带引号输入! 只能一次项!
# s="1+((2x+3)*2+1)+2x=5x"
left, right = s.split("=")
lf=function(left)
rt=function(right)
result=lf-rt
answer=-result[0]/result[1]
print("the answer is:",answer)
相关阅读
js字符串截取函数slice()、substring()、substr()
原文地址为:js字符串截取函数slice()、substring()、substr()摘要在js中字符截取函数有常用的三个slice()、substring()、substr()
当你正在学习如何完全使用 Linux shell 时,你可以能会觉得自己能够对字符串进行操作。 记住,今天q&一个文章的超级用户对读者的一个
有一个项目需要和原生对接,而原生的颜色无法识别rgb,因此出现了这个转换需求。 细分析,这个需求需要: 1. 提取出rgb颜色 ; 2. 转换r
引言 对于初学Java的人来说,在学习String的时候,肯定有无数个人和我们讲过,”尽量不要使用+拼接字符串,效率不好,应该使用append,
背景: 对接第三方接口需要传个age和ageTyoe字段,其中age字段为integer型,ageType取“岁/月/天”,但是我们系统存的年龄格式为N岁M月,