面对这种编程挑战,我首先尝试回答以下问题:
看起来像小型编程语言的问题往往使我想到Lisp。问题是要求我们生成系列:
123 (* 12 3) (+ 12 3) ... (- (- 1 2) 3)
@H_502_17@基本上在3元组
(operator, left, right)
中的左右位置也可以是表达式的二进制表达式。组件的顺序实际上并不重要。Python具有元组,并且在operator
模块中具有针对各种二进制操作的功能。因此,我打算以以下形式构建表达式:(operator.sub, (operator.sub, 1, 2), 3)
@H_502_17@然后可以使用(主要是)简单的递归函数进行评估:
def compute(expr): if isinstance(expr, tuple): op, left, right = expr return op(compute(left), compute(right)) return expr
@H_502_17@减少可能性
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果
5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(operator.sub, (operator.sub, 1, 2), 3)
@H_502_17@然后可以使用(主要是)简单的递归函数进行评估:
def compute(expr): if isinstance(expr, tuple): op, left, right = expr return op(compute(left), compute(right)) return expr
@H_502_17@减少可能性
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果
5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
def compute(expr): if isinstance(expr, tuple): op, left, right = expr return op(compute(left), compute(right)) return expr
@H_502_17@减少可能性
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果
5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
'3|456237490' -> '34|56237490' -> ... 3 '4|56237490' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
基本上在3元组(operator, left,
right)
中的左右位置也可以是表达式的二进制表达式。组件的顺序实际上并不重要。Python具有元组,并且在operator
模块中具有针对各种二进制操作的功能。因此,我打算以以下形式构建表达式:
然后可以使用(主要是)简单的递归函数进行评估:
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?
不幸的是,末尾的数字仍然可以做出重大更改:
我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
它们都给出不同的结果,[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
关于我的实现的一些注意事项。该generate()
函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,都移动标记,并分割第一个数字:
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
基本上在3元组(operator, left,
right)
中的左右位置也可以是表达式的二进制表达式。组件的顺序实际上并不重要。Python具有元组,并且在operator
模块中具有针对各种二进制操作的功能。因此,我打算以以下形式构建表达式:
(operator.sub, (operator.sub, 1, 2), 3)
@H_502_17@然后可以使用(主要是)简单的递归函数进行评估:
def compute(expr): if isinstance(expr, tuple): op, left, right = expr return op(compute(left), compute(right)) return expr
@H_502_17@减少可能性
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果
5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
def compute(expr): if isinstance(expr, tuple): op, left, right = expr return op(compute(left), compute(right)) return expr
@H_502_17@减少可能性
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果
5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
'3|456237490' -> '34|56237490' -> ... 3 '4|56237490' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
然后可以使用(主要是)简单的递归函数进行评估:
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?
不幸的是,末尾的数字仍然可以做出重大更改:
我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
它们都给出不同的结果,[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
关于我的实现的一些注意事项。该generate()
函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,都移动标记,并分割第一个数字:
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
然后可以使用(主要是)简单的递归函数进行评估:
def compute(expr): if isinstance(expr, tuple): op, left, right = expr return op(compute(left), compute(right)) return expr
@H_502_17@减少可能性
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果
5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
'3|456237490' -> '34|56237490' -> ... 3 '4|56237490' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?
不幸的是,末尾的数字仍然可以做出重大更改:
我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
它们都给出不同的结果,[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
关于我的实现的一些注意事项。该generate()
函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,都移动标记,并分割第一个数字:
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
从问题描述来看,似乎给定的每位数字可能有指数级的表达。我们是否可以通过创建所有排列来消除其中的某些部分?
例如,输入一个六位数的数字和目标结果5
。在创建排列的过程中,假设从前四位数字创建了以下表达式,剩下两个要处理:
(* 42 81) '??'
@H_502_17@
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
'3|456237490' -> '34|56237490' -> ... 3 '4|56237490' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?
不幸的是,末尾的数字仍然可以做出重大更改:
我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
它们都给出不同的结果,[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
关于我的实现的一些注意事项。该generate()
函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,都移动标记,并分割第一个数字:
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
3696
是一个很大的数字,从这一点来看,任何表达式甚至都能够得到just的结果5
吗?我们可以完全跳过创建它们吗?
不幸的是,末尾的数字仍然可以做出重大更改:
(+ (* (* 42 81) 0) 5)
@H_502_17@我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
减少工作
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
'3|456237490' -> '34|56237490' -> ... 3 '4|56237490' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
它们都给出不同的结果,[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
关于我的实现的一些注意事项。该generate()
函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,都移动标记,并分割第一个数字:
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
我们可能会避免一些分支,但是我们将不得不考虑大多数表达式。
好吧,鉴于我们实际上必须获得大量表达式的结果,是否还有其他省力的方法?
让我们想象一下,我们正在逐步生成一个序列,这三个最终表达式是一个接一个地生成的:
... (* (- 8 (* 3 6)) 1) (+ (- 8 (* 3 6)) 1) (- (- 8 (* 3 6)) 1) ...
@H_502_17@它们都给出不同的结果,
[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。答案
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
-
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' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
'3|456237490' -> '34|56237490' -> ... 3 '4|56237490' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
它们都给出不同的结果,[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
关于我的实现的一些注意事项。该generate()
函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,都移动标记,并分割第一个数字:
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
它们都给出不同的结果,[12, 13, 11]
但是内部部分(- 8 (* 3 6))
是相同的,并且将永远是12
。我们的解决方案应该利用这一优势。
对于需要剧透的人,我为最初的实现建立了分支,该实现从顶部开始计算每个表达式,对次要的更改进行存储,从而进行计算,最后一个对生成的表达式进行预计算的结果,以及一些小的调整。。
关于我的实现的一些注意事项。该generate()
函数通过考虑字符串中的每个点并创建可能的下一个状态来创建候选表达式。例如,在开始时,都移动标记,并分割第一个数字:
'3|456237490' -> '34|56237490' -> ... 3 '4|56237490' ->
@H_502_17@每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
每个待处理状态都被推送到一个列表,并且每次循环时都会弹出要考虑的当前状态。从最后的状态继续,接下来的可能性是再次移动标记,并拆分数字以形成三个表达式之一。
3 '45|6237490' -> ... (* 3 4) '5|6237490' -> ... (+ 3 4) '5|6237490' -> ... (- 3 4) '5|6237490' -> ...
@H_502_17@到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
到目前为止,我已经优先考虑了操作员的优先权。处理乘法时,我们可能需要重写现有的表达式。考虑:
(+ 1 2) '3|' -> (* (+ 1 2) 3) '' # ??? (+ (+ 1 2) 3) '' (- (+ 1 2) 3) ''
@H_502_17@对于加法和减法,这很好,顺序无关紧要。但是,
2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
对于加法和减法,这很好,顺序无关紧要。但是,2 * 3
必须在之前发生1 + ...
。简而言之,我们需要将乘法推入内部:
(+ 1 2) 3 -> (+ 1 (* 2 3))
@H_502_17@除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
解决方法
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits =
"123"
和target =6
,应返回:["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
[['1','2','3'],['1','23'],['12',['123']]
运营商:
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,
2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。我还尝试使用以下替代方法来加速eval()函数:
if eval(temp) == target:
要么
exp_as_func = eval('lambda: ' + temp) if exp_as_func() == target:
要么
compiled = compile(temp,'<string>','eval') if compiled == target:
使用Python 3,所有这些花费的时间仍然差不多。
码:
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,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,)): res.append(x) if action == 0: yield "".join(res) res = [] start = time.clock() #####PRODUCT GENERATES (0,1 APPEND NEXT ITEM. elementCombo = [list(generate_combination(digits,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:",target))
[['1','2','3'],['1','23'],['12',['123']]
{0: [()],1: [('+',),('-',('*',)],2: [('+','+'),('+','-'),'*'),'*')]}
if eval(temp) == target:
exp_as_func = eval('lambda: ' + temp)
if exp_as_func() == target:
compiled = compile(temp,'<string>','eval')
if compiled == target:
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,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))
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,)):
res.append(x)
if action == 0:
yield "".join(res)
res = []
start = time.clock()
#####PRODUCT GENERATES (0,1 APPEND NEXT ITEM.
elementCombo = [list(generate_combination(digits,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:",target))
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。
问题表示为:给定一个仅包含数字0-9和目标值的字符串,返回通过在数字之间添加一些二进制运算符(+,-或*)而创建的所有表达式,以便它们求和为目标值。在某些情况下,可能没有任何二进制运算符将创建有效的表达式,在这种情况下,该函数应返回一个空数组。新表达式中的数字不应包含前导零。
该函数应返回按字典顺序排序的求值为目标的所有有效表达式。
例如:
digits ="123"
和target = 6
,应返回: ["1*2*3","1+2+3"]
我当前的算法如下。它有点慢,所以我正在寻找一种更有效的方法来解决该问题。我目前的算法产生操作数和运算符的所有组合。对于上面的示例,它产生
操作数:
运营商:
然后,它将所有可能的操作数和运算符组合在一起并进行评估。
这些数字有一个约束,2 ≤ digits.length ≤ 10.
因此,它还算不错,但是对于这种长度为10的数字,它大约需要4.3秒,而该数字最多需要4秒。
我还尝试使用以下替代方法来加速eval()函数:
要么
要么
使用Python 3,所有这些花费的时间仍然差不多。
码:
使用计算器函数(没有eval())的代码几乎具有相同的速度:
除了存储执行操作的功能外,还有一些巧妙的方法可以存储有关操作的更多信息。对于这个问题,这并不是真正需要的,也不需要其他可能的转换,例如组合多个表达式或排除不相关的部分。
最后的实现说明,很困难,我既使迭代的方向又使表达式的布局(最初)向后。