LeetCode 640 求解方程 Solve the Equation
难度:Medium
标签:字符串解析、模拟、代数合并同类项
题目原文
题目描述
求解一个给定的一元一次方程,将x以字符串"x=#value"的形式返回。该方程仅包含+,-操作,变量x和对应的系数。
三种返回情况:
- 如果方程没有解:返回
"No solution" - 如果方程有无穷多解:返回
"Infinite solutions" - 如果只有唯一解,题目保证解是整数,返回
"x=数字"
约束
- 方程有且仅有一个
= - 方程由整数(绝对值0~100,无前置零)和变量
x组成 - 字符串长度范围 3 ≤ equation.length ≤1000
示例
示例1
输入:"x+5-3+x=6+x-2"
输出:"x=2"
示例2
输入:"x=x"
输出:"Infinite solutions"
示例3
输入:"2x=x"
输出:"x=0"
示例4
输入:"x=x+2"
输出:"No solution"
费曼学习法拆解本题(用大白话,讲给小白)
第一步:看懂题目本质
这题本质就是手写解方程:合并同类项。
一元一次方程通用形式:
a⋅x+b=c⋅x+da\cdot x + b = c\cdot x + da⋅x+b=c⋅x+d
移项,把所有x项挪左边,常数挪右边:
(a−c)⋅x=d−b(a-c)\cdot x = d-b(a−c)⋅x=d−b
令:
x_coeff = a - c合并后x的总系数const = d - b合并后的常数
然后分3种数学场景:
x_coeff != 0:唯一解x=constx_coeffx=\frac{const}{x\_coeff}x=x_coeffconstx_coeff ==0,const ==0:0x=0 → 任何x都成立,无穷解x_coeff ==0,const !=0:0x=非0 → 无解
难点不是数学,是字符串解析!
要从字符串里拆分每一项,处理坑:
x等价1x-x等价-1x0x,100x正常系数- 表达式开头没有加号,例如
"x+3"
第二步:两种解法思路对比
解法1:通用解析函数(推荐,面试首选)
写一个子函数parse(表达式字符串),输入一段不带=的式子,返回(x总系数,常数总和)
- 遍历表达式字符,记录当前项符号
- 读到数字,收集数字;读到x,识别为x项
- 解析完等号左边、右边
- 合并得到
(a-c)x = d-b,判断三种情况
✅优点:逻辑干净,不依赖正则,好理解,边界好控制
❌缺点:需要手动遍历字符,要细心处理x缺省系数(x=1x,-x=-1x)
解法2:正则分割(简洁,工程写代码方便)
利用正则把所有项提取出来,循环处理每一项
✅优点:代码简短
❌缺点:正则需要记忆,面试写正则容易写错
我们重点讲解法1,附带完整带逐行注释Python代码。
第三步:踩坑清单(费曼找错误)
坑1:x不是0x,是1x;-x是-1x,最容易错
坑2:区分0x(系数0)和x(系数1)
坑3:移项规则:右边的所有项移左边,符号全部翻转
坑4:0x=0无穷解;0x=5无解
第四步:现实应用场景举例
- 在线数学计算器:网页输入一元一次方程字符串,自动求解;很多学生数学工具底层就是这种字符串解析
- 符号计算库:SymPy这类Python符号库,底层就是解析表达式、合并同类项(本题是极简版本)
- 教学系统:在线做题平台,学生输入方程,程序自动判分、自动解方程
- 配置公式引擎:低代码平台,用户自定义计算公式,解析字符串表达式
Python代码【解法1:手写遍历解析,每行详细注释】
classSolution:defsolveEquation(self,equation:str)->str:""" 主函数:接收方程字符串,返回求解结果 :param equation: 方程字符串,中间包含一个'=',例如"x+5-3+x=6+x-2" :return: 结果字符串,三选一 "x=#val", "No solution", "Infinite solutions" """defparse(expr:str):""" 子函数:解析等号单侧表达式,返回(x系数总和,常数总和) :param expr: 不带等号的表达式,如 "x+5-3+x" :return: tuple (coef_x, const_num) """coef_x=0# 存储所有x项的系数总和const_num=0# 存储所有常数项总和n=len(expr)# 表达式字符串总长度i=0# 当前遍历字符下标sign=1# 当前项的符号,默认正号(表达式开头)whilei<n:# 遇到加号:符号置为正,下标+1继续ifexpr[i]=='+':sign=1i+=1# 遇到减号:符号置为负,下标+1继续elifexpr[i]=='-':sign=-1i+=1else:# 当前字符是数字或者x,开始提取当前项j=i# j向后移动,直到不是数字为止,截取数字部分whilej<nandexpr[j].isdigit():j+=1# 取出i到j之间的数字字符串num_str=expr[i:j]# 如果num_str为空,说明直接是x(没有写系数,例如x、-x)num=int(num_str)ifnum_strelse1# 判断j位置是不是x,代表当前项是x项ifj<nandexpr[j]=='x':# 累加 x系数:符号 * 数值coef_x+=sign*num j+=1# 跳过x字符else:# 不是x,这一项是常数const_num+=sign*num# i跳到j,处理下一项i=j# 返回解析得到的x系数,常数returncoef_x,const_num# 以等号分割,拆成左右两段表达式left_expr,right_expr=equation.split('=')# 分别解析左右两边left_x,left_const=parse(left_expr)right_x,right_const=parse(right_expr)# 移项:(left_x - right_x)*x = right_const - left_consttotal_x_coef=left_x-right_x total_const=right_const-left_const# 判断三种情况iftotal_x_coef!=0:# 唯一解,x = total_const / total_x_coefans_x=total_const//total_x_coefreturnf"x={ans_x}"else:# x系数等于0iftotal_const==0:# 0x =0,无穷多解return"Infinite solutions"else:# 0x=非0,无解return"No solution"# ========= 测试用例 =========if__name__=="__main__":sol=Solution()print(sol.solveEquation("x+5-3+x=6+x-2"))# x=2print(sol.solveEquation("x=x"))# Infinite solutionsprint(sol.solveEquation("2x=x"))# x=0print(sol.solveEquation("x=x+2"))# No solutionprint(sol.solveEquation("-x=-1"))# x=1解法2:正则分割方案(简洁版,带注释)
importreclassSolution:defsolveEquation(self,equation:str)->str:defparse(s):coef_x=0const=0# 在表达式最前面补+,方便正则统一提取所有带符号项terms=re.findall(r'[+-]?\d*x?','+'+s)forterminterms:ifnotterm:continueif'x'interm:# x项t=term[:-1]ift=='+'ort=='':coef_x+=1elift=='-':coef_x-=1else:coef_x+=int(t)else:#常数项const+=int(term)returncoef_x,const left,right=equation.split("=")lx,lc=parse(left)rx,rc=parse(right)cx=lx-rx cn=rc-lcifcx!=0:returnf"x={cn//cx}"else:return"Infinite solutions"ifcn==0else"No solution"#测试if__name__=="__main__":obj=Solution()print(obj.solveEquation("x+5-3+x=6+x-2"))复杂度分析
- 时间复杂度O(N):N是方程字符串长度,每个字符遍历一次
- 空间复杂度O(1):只用固定数量变量保存系数,不计输入输出存储
费曼复盘总结
这道题核心考点:字符串词法解析 + 合并同类项。
数学逻辑很简单,难点全在处理字符串的特殊情况:x省略系数1、-x省略系数-1。
面试推荐手写遍历版本,正则版本虽然简短,但面试官更想看你手动解析字符串的能力。