高效的算法可根据特定目标组成有效的表达式

2023-11-24

该问题表述为:给定一个仅包含数字 0-9 和一个目标值的字符串,返回通过在数字之间添加一些二元运算符(+、- 或 *)创建的所有表达式,以便它们计算为目标值。在某些情况下,可能没有任何二元运算符可以创建有效的表达式,在这种情况下,函数应返回空数组。新表达式中的数字不应包含前导零。

该函数应返回计算结果为目标的所有有效表达式,并按字典顺序排序。

例如:

数字="123"和目标=6,应该返回:["1*2*3", "1+2+3"]

我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决这个问题。我当前的算法生成操作数和运算符的所有组合。对于上面的例子,它产生

操作数:

[['1', '2', '3'], ['1', '23'], ['12', '3'], ['123']]

运营商:

{0: [()], 1: [('+',), ('-',), ('*',)], 2: [('+', '+'), ('+', '-'), ('+', '*'), ('-', '+'), ('-', '-'), ('-', '*'), ('*', '+'), ('*', '-'), ('*', '*')]}

然后,它组合操作数和运算符的所有可能组合并评估每个组合。

数字有一个约束2 ≤ digits.length ≤ 10.所以它并没有那么糟糕,但是使用这个算法,长度为 10 的数字需要大约 4.3 秒,而它应该只需要 4 秒(最大值)。

我还尝试使用以下替代方案来加速 eval() 函数:

if eval(temp) == target:

or

exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:

or

compiled = compile(temp, '<string>', 'eval')
if compiled == target:

使用 Python 3,所有这些仍然需要大约相同的时间。

Code:

import itertools
import time

def getValidExp(digits, target):    
    def getSign_combination(length):
        signCombo = {}
        for i in range(0, length):
            signCombo[i] = [c for c in itertools.product(('+', '-', '*'), repeat=i)]
        return signCombo

    def generate_combination(source, comb):
        res = []
        for x, action in zip(source, comb + (0,)):      
            res.append(x)
            if action == 0:
                #####IF ITS A 0, YIELD STRING.  IF NOT COMBINE NEXT ONE
                yield "".join(res)
                res = []


    #####PRODUCT GENERATES (0,0,1).  ALL COMBINATIONS.  0 MEANS BY ITSELF, 1 APPEND NEXT ITEM.

    elementCombo = [list(generate_combination(digits, c)) for c in itertools.product((0, 1), repeat=len(digits) - 1)]

    signCombo = getSign_combination(len(digits))

    result = []
    for e in elementCombo:
        signs = signCombo[len(e)-1]

        for i,sign in enumerate(signs):

            temp = [ item for tple in zip(e, sign) for item in tple ]
            temp.append(e[-1])
            temp = "".join(temp)

            try:
                if eval(temp) == target:
                    result.append(temp)
            except:
                pass

    return sorted(result)

digits = "3456237490"
target = 9180
print("Answer:", getValidExp(digits, target))

使用计算器函数(无 eval())的代码几乎具有相同的速度:

from itertools import combinations, permutations
import itertools
import time

def getValidExp(digits, target):

    def calculate(s):
        operands, operators = [], []
        operand = ""
        for i in reversed(range(len(s))):
            if s[i].isdigit():
                operand += s[i]
                if i == 0 or not s[i - 1].isdigit():
                    operands.append(int(operand[::-1]))
                    operand = ""
            elif s[i] == '*':
                operators.append(s[i])
            elif s[i] == '+' or s[i] == '-':
                while operators and operators[-1] == '*':
                    compute(operands, operators)
                operators.append(s[i])

        while operators:
            compute(operands, operators)

        return operands[-1]

    def compute(operands, operators):
        left, right = operands.pop(), operands.pop()
        op = operators.pop()
        if op == '+':
            operands.append(left + right)
        elif op == '-':
            operands.append(left - right)
        elif op == '*':
            operands.append(left * right)

    def getSign_combination(length):
        signCombo = {}
        for i in range(0, length):
            signCombo[i] = [c for c in itertools.product(('+', '-', '*'), repeat=i)]
        return signCombo

    def generate_combination(source, comb):
        res = []
        for x, action in zip(source, comb + (0,)):
            res.append(x)
            if action == 0:
                yield "".join(res)
                res = []

    start = time.clock()

    #####PRODUCT GENERATES (0,0,1).  ALL COMBINATIONS.  0 MEANS BY ITSELF, 1 APPEND NEXT ITEM.
    elementCombo = [list(generate_combination(digits, c)) for c in itertools.product((0, 1), repeat=len(digits) - 1)]

    signCombo = getSign_combination(len(digits))

    result = []
    for e in elementCombo:
        signs = signCombo[len(e)-1]
        for i,sign in enumerate(signs):
            temp = ""
            valid = True

            for num in e:
                if num[0] == '0' and len(num) > 1:
                    valid = False
                    break

            if valid:
                for num,operator in zip(e,sign):
                    temp += num
                    temp += operator

                temp += e[-1]

                ####USING CALCULATOR CODE
                if calculate(temp) == target:
                    result.append(temp)

    print(time.clock() - start)
    return sorted(result)


digits = "3456237490"
target = 9180
print("Answer:", getValidExp(digits, target))

面对这种编程挑战,我首先尝试回答以下问题:

  • 表达式应该如何表示?
  • 我们可以减少可能的表达式数量吗?
  • 我们可以为每个表达式做更少的工作吗?

表示表达式

看起来像小型编程语言的问题往往会让我想到 Lisp。问题是要求我们生成该系列:

123
(* 12 3)
(+ 12 3)
...
(- (- 1 2) 3)

基本上是 3 元组的二进制表达式(operator, left, right)其中 left 和 right 也可以是表达式。组件的顺序实际上并不重要。 Python 有元组,并且在operator模块它具有各种二进制操作的功能。因此,我计划以以下形式构建表达式:

(operator.sub, (operator.sub, 1, 2), 3)

然后可以使用(大部分)简单的递归函数来评估:

def compute(expr):
    if isinstance(expr, tuple):
            op, left, right = expr
            return op(compute(left), compute(right))
    return expr

减少可能性

从问题描述来看,似乎给定的每个数字都有指数数量的可能表达式。我们可以通过创建所有排列来消除其中一些部分吗?

例如,采用六位数字输入和目标结果5。在创建排列的过程中,假设已经从前四位数字创建了以下表达式,并且还剩下两个需要处理:

(* 42 81) '??'

3696是一个很大的数字,从这一点开始的任何表达式是否都能够得到结果5?我们可以完全跳过创建它们吗?

不幸的是,接近末尾的数字仍然可以做出重大改变:

(+ (* (* 42 81) 0) 5)

可能有一些分支我们可以避免,但我们必须考虑大多数表达式。

做更少的工作

好吧,考虑到我们必须实际获得大量表达式的结果,是否有其他方法可以节省精力?

让我们想象一下,我们正在生成一个序列,这三个最终表达式依次生成:

...
(* (- 8 (* 3 6)) 1)
(+ (- 8 (* 3 6)) 1)
(- (- 8 (* 3 6)) 1)
...

他们都给出了不同的结果,[12, 13, 11],但是那个内部部分(- 8 (* 3 6))是一样的,并且永远是12。我们的解决方案应该考虑利用这一点。

一个答案

对于需要剧透的人,我已经放了branches for an 初步实施从顶部开始计算每个表达式,a记忆计算的微小变化,最后一个是预先计算结果随着表达式的生成加上一些小调整.

  • 17.40s elapsed 6180k max mem问题原文
  • 20.60s elapsed 6284k max mem没有从问题中评估
  • 4.65s elapsed 5356k max mem我的首字母
  • 2.71s elapsed 5316k max mem我的记忆
  • 1.50s elapsed 5356k max mem我预先计算的

关于我的实现的一些注释。这generate()函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,两者都沿着移动标记,并分开第一个数字:

'3|456237490' ->
    '34|56237490' -> ...
    3 '4|56237490' ->

每个待处理状态都被推送到一个列表中,并且每次循环时都会弹出当前要考虑的状态。从最后的状态继续,下一个可能性是再次移动标记,并分割一个数字以形成三个表达式之一。

        3 '45|6237490' -> ...
        (* 3 4) '5|6237490' -> ...
        (+ 3 4) '5|6237490' -> ...
        (- 3 4) '5|6237490' -> ...

到目前为止,我已经掩盖了操作符优先级的一个问题。在处理乘法时,我们可能需要重写现有的表达式。考虑:

(+ 1 2) '3|' ->
    (* (+ 1 2) 3) '' # ???
    (+ (+ 1 2) 3) ''
    (- (+ 1 2) 3) ''

对于加法和减法来说这很好,顺序并不重要。然而,2 * 3必须发生在之前1 + ...。简而言之,我们需要将乘法推入内部:

(+ 1 2) 3 -> (+ 1 (* 2 3))

有一些巧妙的方法可以通过存储更多有关操作的信息来处理此问题,而不仅仅是执行它们的函数。对于这个问题来说,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或分解出不相关的部分。

最后的实现说明,为了增加难度,我将迭代方向和(最初)表达式的布局都向后做了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

高效的算法可根据特定目标组成有效的表达式 的相关文章

  • python,在数据框中存储字典

    我构建了一个 pandas 数据框 它在每个单元格中存储一个简单的字典 例如 Sales 0 Revenue 0 我可以通过以下方式从数据帧中检索特定值 df columnA index100 Revenue 但现在我想绘制一个图表 其中包
  • 使用 os.popen 在 python 中创建列表

    以前 我已经能够使用类似于以下内容的命令创建列表 os popen ls fits gt samplelist 现在 我尝试通过按编号将文件分组来将文件组织到列表中 这些文件的命名如下 Name 0000 J fits Name 0001
  • DJANGO:如何列出_显示反向外键属性?

    我正在构建一个网络应用程序来跟踪一个人借阅的图书馆书籍 我有以下型号 class Person models Model name models CharField max length 100 def unicode self retur
  • 如何在不访问 hg 的情况下提取 BitBucket 存储库

    我想知道是否可以在不访问 hg 的情况下将私人 Mercurial 存储库拉到服务器上 我有 SSH 访问权限 但无法安装 HG 我正在考虑某种使用 http 访问的 Python 脚本或其他东西 但我不确定 我还认为这可能只有通过公共回购
  • 如何在Python中测量时间?

    我想启动我的程序 测量程序启动的时间 然后等待几秒钟 按下按钮 K RIGHT 并测量按下按钮的时间 我正在使用 Pygame 来注册 Keydown 但在我下面的代码中它没有注册我的 Keydown 我在这里做错了什么 start tim
  • Python 使用 ssl.getpeercert() 从 URL 获取通用名称

    我正在尝试获取证书颁发者信息 通用名称 但链接中的代码不适用于某些 URL 如何在 python 中获取证书颁发者信息 https stackoverflow com questions 30862099 how can i get cer
  • 如何使Python格式的浮点数具有一定数量的有效数字?

    我希望我的 Python 2 4 3 输出数字具有特定的格式 具体来说 如果数字是有效数字 6 位有效数字 则仅输出 6 位有效数字 A 显示了 Python 如何编写浮点数 B 显示了我希望它们如何书写 我怎样才能让Python以这种方式
  • Google Cloud Functions 中的 Python

    Google Cloud Functions 可以使用 sklearn pandas 等包处理 python 吗 如果是这样 有人可以向我指出如何做到这一点的资源方向 我已经搜索了一段时间 似乎这是不可能的 我找到的只是将基本 python
  • Google 文档如何处理编辑冲突?

    我一直在尝试编写自己的 Javascript 编辑器 其功能类似于 Google Docs 允许多人同时使用 我不明白一件事 假设用户 A 和用户 B 直接相互连接 网络延迟为 10 毫秒 我假设编辑器使用 diff 系统 据我了解 Doc
  • 使用 xlwings 排序(pywin32)

    我需要使用 python 按给定行对 Excel 电子表格进行排序 为了进行测试 我使用以下数据 在名为 xlwings sorting xlsx 的文件中 Numbers Letters Letters 2 7 A L 6 B K 5 C
  • Sendmail Errno[61] 连接被拒绝

    我一直在尝试让我的应用程序将一些输出的文本邮寄到电子邮件中 为了简单起见 我隔离了脚本 import smtplib import sys import os SERVER localhost FROM os getlogin TO raw
  • manage.pysyncdb 不会为某些模型添加表

    今天我的第二个不太熟练的问题 我有一个 django 项目 其中安装了四个应用程序 当我运行manage py syndb时 它只为其中两个创建表 据我所知 我的任何模型文件都没有问题 并且所有应用程序都在我的设置文件中的 INSTALLE
  • 如何在 python 中从相机(或网络摄像头)捕获视频(和音频)

    我正在寻找一个解决方案 无论是在Linux还是在Windows中 它都可以让我 同时从我的网络摄像头和麦克风录制视频 音频 将其另存为文件 AVI 或 mpg 或其他文件 录制时在屏幕上显示视频 就我而言 压缩不是问题 实际上我更喜欢捕获
  • 基本的 Python OpenCV 裁剪和调整大小

    有人可以帮我一些裁剪算法吗 它的 openCV 我想弄清楚这一点 我知道方法是crop image y y1 x x1 如果我有一个带有 new dimensionXxnew dimensionY 像素的图像 并且我想将其裁剪为相同的宽度
  • 根据另一个参数的值添加参数

    根据输入之一 我想初始化某些对象 这些对象的值将是其余参数的默认值 因此 即使在 parser parse args 之前 我也需要参数之一的值 我如何使用 python argparse 模块来实现这一点 所有选项都将作为一个命令行给出
  • 如何为 PyDev 制作文件模板?

    我希望在我创建的每个新文件的顶部都有一些有关许可证 作者等的样板信息 但我找不到要勾选的正确框 基本上 我想创建一个新文件 并已将其填充 在顶部 author Me license something copyright something
  • 从 pandas 数据帧中提取阶段/段以及相应的时间戳

    我有以下数据框 Sleep Stage Time hh mm ss Event Duration s 0 SLEEP S0 23 27 14 SLEEP S0 30 1 SLEEP S0 23 27 44 SLEEP S0 30 2 SLE
  • 处理流星中的长服务器端计算

    我正在使用 jimp https www npmjs com package jimp https www npmjs com package jimp 在meteor JS中生成图像服务器端 换句话说 我正在使用递归算法 计算 图像的像素
  • Python BeautifulSoup 循环表数据

    这里对 Python 非常陌生 我正在尝试从此页面捕获一些数据这一页 https us diablo3 com en item helm 我正在尝试获取两个列表中捕获的项目名称和项目类型 我稍后可以弄清楚如何将它们连接到一张表中 任何帮助都
  • 以任意深度嵌套 defaultdict

    我想嵌套任意数量的默认字典 如下所示 from collections import defaultdict D defaultdict lambda defaultdict int 正如所描述的那样工作正常earlier https st

随机推荐

  • Android Context 线程安全吗?

    当我在 AsyncTask doInBackground 中使用 Android 上下文时 它是线程安全的吗 上下文是通过构造函数或通过周围 Activity 的 getApplicationContext 提供的 这个简单的问题在 sta
  • onAttach 活动为空

    在创建片段时 我遇到 getActivity 为空 因此 为了缩小问题范围 我在 onAttach Activity Activity 中保留了 Activity 的本地副本 根据定义 这是附加到 Activity 时的情况 但是 我在 o
  • 访问列表中类的属性

    我看到很多类似的问题 但没有一个有直接答案 我有一个List
  • 从 Crashlytics SDK 迁移到 Fabric 后出现构建错误

    最近 我们已将组织的 Crashlytics 帐户升级到 Fabric 我正在尝试在现有应用程序中用新的 Fabric SDK 替换旧的 Crashlytics SDK 我已经关注了迁移说明 而且基本上很轻松 除了我现在在尝试编译时收到构建
  • 将变量传递给带有字边界的 RegExp

    我必须传递变量的 RegExp 值并指向字边界 我有一个字符串要检查它是否包含变量值 我不知道如何将变量值和单词边界属性传递给正则表达式 所以像这样 var sa Sample var re new RegExp b sa alert re
  • Android 应用程序永远不会自动更新

    我在 Play 商店中有一个有点不寻常的 Android 应用程序 它在专用设备上 24 7 运行 它收集传感器数据 并不意味着在用于其他用途的手机上运行 我希望该应用程序能够在没有用户交互的情况下自动更新 但这似乎永远不会发生 为什么会这
  • 删除javascript中的第一个孩子

    我正在尝试删除第一个li in an ol使用 DOMremoveChild 但由于某种原因它不起作用 这是我的 JavaScript document getElementById queue removeChild document g
  • CrystalReports ReportDocument 数据库连接内存泄漏

    我过去几天一直在研究这个问题 但似乎无法弄清楚 我有一个c WinForms应用程序使用ReportDocument加载报表并将其放入 Crystal Report Viewer 中 以便用户可以预览它 目的是预览不同的统计数据 并且表单永
  • C++11 中局部静态变量初始化是线程安全的吗? [复制]

    这个问题在这里已经有答案了 我知道这是一个经常被问到的问题 但由于有很多变体 我想重申一下 并希望能得到一个反映当前状态的答案 就像是 Logger g logger static Logger lg return lg 变量 lg 的构造
  • setDragImage 不工作 - Java 7

    我正在尝试设置代码 以便用户可以从 JTable 拖动到 JList 并使用 TransferHandler 中的 Java 7 函数 setDragImage 自定义拖动图像 我在java教程网站上找到了一个示例 他们在其中教授Drag
  • SyntaxError:未终止的字符串文字 标记在字符串变量中不起作用

    请看我的代码 var id 1 var htmlText div ul class rtabs ul div class panel container div div div div div style display none Blah
  • 按嵌套对象的一个​​属性对对象数组进行排序

    我需要通过对象属性之一的一个属性来比较对象数组 我在做 List
  • 如何将 accdb 转换为 postgres 数据库

    我需要使用 accdb 数据库 为此需要将其导入 PostgreSQL 我相信这将是一个简单而直接的问题 我预计它已经解决了 但我没有找到一个简单的解决方案 我要补充一点 我无权访问 Access 笑 并且我的解决方案松散地依赖于此 如果那
  • 从 .crt 和 .key 文件创建 .jks 是否可能

    我向权威机构申请了 SSL 证书 首先 我在计算机上创建了一个 csr 和一个 key 文件并保存了它们 我发送了 csr 并取回了 crt 文件和我安装在服务器上的其他文件 对于具有 SSL 连接的 Apache 服务器来说 一切正常 但
  • OpenCart:如何准确填充 oc_category_path

    我使用在线服务将数据从其他电子商务网站传输到OpenCart一切似乎都已正确转移 然而 产品类别存在一个问题 类别已转移至oc category桌子 但是 看起来还有另一张表叫做oc category path如果我希望能够在管理员中编辑我
  • 使用 OpenGL ES 2.0 进行 GPGPU 编程

    我正在尝试在 GPU 上进行一些图像处理 例如中值 模糊 亮度等 总体思路是做类似的事情这个框架来自 GPU 宝石 1 我能够编写 GLSL 片段着色器来处理像素 因为我一直在效果设计器应用程序中尝试不同的东西 然而我不确定我应该如何完成任
  • .NET 的哪些部分在 iPhone 开发者的 Monotouch 中不可用?

    哪些键绑定未包含在内 您可以在以下位置找到 MonoTouch 的完整限制列表 Xamarin MonoTouch 中不可用的 NET 功能的简短列表 动态语言运行时 DLR 通用虚拟方法 泛型类型中的 P 调用 作为字典键的值类型 系统
  • 带索引变量的 Sympy 求和

    我尝试使用带有索引变量的 Sum 创建一个 sympy 表达式 如前所述here但是 我无法对该表达式进行羔羊化并给出一个数组来计算总和 这不可能吗 也许像这样 s Sum Indexed x i i 1 3 f lambda x Subs
  • 如何在 Rails 中设置 url 助手的默认主机?

    我想做这样的事情 config default host www subdomain example com 在我的一些配置文件中 这样object url帮手 ActionView Helpers UrlHelper 生成以以下内容开头的
  • 高效的算法可根据特定目标组成有效的表达式

    该问题表述为 给定一个仅包含数字 0 9 和一个目标值的字符串 返回通过在数字之间添加一些二元运算符 或 创建的所有表达式 以便它们计算为目标值 在某些情况下 可能没有任何二元运算符可以创建有效的表达式 在这种情况下 函数应返回空数组 新表