解单变量线性方程

Solving a linear equation in one variable

本文关键字:线性方程 变量 单变量      更新时间:2023-10-16

什么将是最有效的算法来解决线性方程在一个变量给定的字符串输入到一个函数?例如,对于输入字符串:

"x + 9 - 2 - 4 + x = - x + 5 - 1 + 3 - x"

输出应为1。

我正在考虑使用堆栈并在遇到字符串中的空格时将每个字符串标记压入其中。如果输入是波兰符号,那么从堆栈中弹出数字以获得结果会更容易,但我不确定这里采取什么方法。

这是一个面试问题。

一旦你算出方程a * x + b = 0中的系数ab,解线性方程(我希望)对你来说非常容易。

所以,问题的困难部分是解析表达式并"评估"它以找到系数。您的示例表达式非常简单,它只使用一元-,二进制-,二进制+操作符。还有=,你可以特别处理。

从问题中不清楚解决方案是否也应该处理包含二进制*/或括号的表达式。我想知道这个面试问题是不是有意的:

  • 让你写一些简单的代码,或者
  • 让你在写任何东西之前问一下问题的真正范围是什么。

都是很重要的技能:-)

这个问题甚至可能是有意的:

  • 将那些有很多编写解析器经验的人(他们会尽可能快地解决问题)与那些没有编写解析器经验的人(他们可能会在几分钟内努力解决问题,至少没有一些提示)分开。
无论如何,为了允许将来更复杂的需求,有两种常见的方法来解析算术表达式:递归下降或Dijkstra的分流码算法。您可以查找这些,如果您只需要1.0版本中的简单表达式,那么您可以使用Dijkstra算法的简化形式。然后,一旦您解析了表达式,您需要对其进行评估:使用x中的线性表达式值,并将=解释为具有最低优先级的操作符,这意味着"减去"。结果是x中的线性表达式等于0

如果你不需要复杂的表达式,那么你可以直接从左到右计算这个简单的例子,一旦你把它标记了[*]:

x
x + 9
// set the "we've found minus sign" bit to negate the first thing that follows
x + 7 // and clear the negative bit
x + 3
2 * x + 3
// set the "we've found the equals sign" bit to negate everything that follows
3 * x + 3
3 * x - 2
3 * x - 1
3 * x - 4
4 * x - 4

最后将a * x + b = 0解为x = - b/a

[*]示例标记化代码,在Python中:

acc = None
for idx, ch in enumerate(input):
    if ch in '1234567890':
        if acc is None: acc = 0
        acc = 10 * acc + int(ch)
        continue
    if acc != None:
        yield acc
        acc = None
    if ch in '+-=x':
        yield ch
    elif ch == ' ':
        pass
    else:
        raise ValueError('illegal character "%s" at %d' % (ch, idx))

另一个标记化示例代码,同样在Python中,假设标记之间总是有空格,如示例中所示。这就把令牌验证留给了解析器:

return input.split()

可以使用一些简单的伪代码来解决这个问题

 function(stinrgToParse){
      arrayoftokens = stringToParse.match(RegexMatching);
      foreach(arrayoftokens as token)
      {
         //now step through the tokens and determine what they are
         //and store the neccesary information.
      }
      //Use the above information to do the arithmetic.
      //count the number of times a variable appears positive and negative
      //do the arithmetic.
      //add up the numbers both positive and negative. 
      //return the result.
 }

第一件事是解析字符串,识别各种标记(数字、变量和操作符),以便通过给操作符适当的优先级来形成表达式树。

正则表达式可以提供帮助,但这不是唯一的方法(像boost::spirit这样的语法解析器也很好,你甚至可以运行自己的语法解析器:这都是"查找和追偿")。

然后可以通过减少执行那些处理常量的操作的节点,并通过将变量相关的操作分组,相应地执行这些操作来操纵树。

这将递归地继续下去,直到您保留与变量相关的节点和常量节点。

在这一点解被简单地计算。

它们基本上是导致产生解释器或编译器的相同原则。

考虑:

from operator import add, sub
def ab(expr):
    a, b, op = 0, 0, add
    for t in expr.split():
        if   t == '+': op = add
        elif t == '-': op = sub
        elif t == 'x': a = op(a, 1)
        else         : b = op(b, int(t))
    return a, b

给定一个表达式,如1 + x - 2 - x...,将其转换为规范形式ax+b,并返回一对系数(a,b)

现在,让我们从方程的两个部分得到系数:

le, ri = equation.split('=')    
a1, b1 = ab(le)
a2, b2 = ab(ri)    

,最终解出平凡方程a1*x + b1 = a2*x + b2:

x = (b2 - b1) / (a1 - a2)

当然,这只解决了这个特定的例子,没有操作符优先级或括号。要支持后者,您需要一个解析器,可能是递归下降解析器,手工编写会更简单。