题目:给定一个数组,问:这组数进行四则运算(每个数必须用到,且只用一次)可以得到多少个不同的值?
如何划分:表达式是一步一步算的,划分的方法就是哪个数先加入和表达式的当前值进行计算,并且有4种计算方式(其实是6种,减法和除法各2种顺序)
def uniqueValues(A):
ans = set()
def dfs(i, value):
if i == len(A): ans.add(value)
else:
for j in xrange(i, len(A)):
A[i], A[j] = A[j], A[i]
if i == 0:
dfs(i + 1, value + A[i])
else:
dfs(i + 1, value + A[i])
dfs(i + 1, value - A[i])
dfs(i + 1, A[i] - value)
dfs(i + 1, value * A[i])
dfs(i + 1, value / A[i])
if value != 0: dfs(i + 1, A[i] / value)
A[i], A[j] = A[j], A[i]
dfs(0, 0)
return ans
题目2,给定一个数的集合,打印所有可以生成的不同表达式
划分:以最后进行的计算作为划分,是一个不相交且完备的划分。分治法,以最后进行的计算为轴,把集合分成2组,递归求解两边边的集合,然后组合最后的表达式集合。
cache = {}
def expressions(A):
if len(A) == 1: return [str(A[0])]
else:
A.sort()
key = tuple(A)
if key in cache.keys(): return cache[key]
left, right, ans = [], [], []
def group(i, leftCount, rightCount):
if i == len(A):
for exp1 in expressions(left):
for exp2 in expressions(right):
exp1 = exp1 if exp1.isdigit() or exp1[0] == '(' else '(' + exp1 + ')'
exp2 = exp2 if exp2.isdigit() or exp2[0] == '(' else '(' + exp2 + ')'
for op in '+-*/': ans.append(exp1 + op + exp2)
ans.append(exp2 + '-' + exp1)
ans.append(exp2 + '/' + exp1)
else:
if leftCount < len(A) - 1:
left.append(A[i])
group(i + 1, leftCount + 1, rightCount)
left.pop()
if leftCount == 0: return
if rightCount < len(A) - 1:
right.append(A[i])
group(i + 1, leftCount, rightCount + 1)
right.pop()
group(0, 0, 0)
cache[tuple(A)] = ans
return ans
做法2:不需要存储,一般dfs,但是有重复,是正确结果的2倍
def expressions(A, i, exp):
if len(A) == i: print exp
else:
for j in xrange(i, len(A)):
A[i], A[j] = A[j], A[i]
if i == 0: expressions(A, i + 1, str(A[i]))
else:
for op in '+-*/': expressions(A, i + 1, '(' + exp + op + str(A[i]) +')')
expressions(A, i + 1, '(' + str(A[i]) + '-' + exp + ')')
expressions(A, i + 1, '(' + str(A[i]) + '/' + exp + ')')
A[i], A[j] = A[j], A[i]
题目3 给定一组数,添加操作符使得表达式值为给定target(类似的问法:添加操作符使得等式成立)
把表达式看做是term的和,term由factor组成。t是表达式最后一个term,
def solve(A, i, v, t, target, e):
if i == len(A):
if v == target: print e
else:
if i == 0: solve(A, i + 1, A[i], A[i], target, str(A[i]))
else:
solve(A, i + 1, v + A[i], A[i], target, e + '+' + str(A[i]))
solve(A, i + 1, v - A[i], -A[i], target, e + '-' + str(A[i]))
solve(A, i + 1, v - t + t * A[i], t * A[i], target, e + '*' + str(A[i]))
if A[i] != 0: solve(A, i + 1, v - t + t / A[i], t / A[i], target, e + '/' + str(A[i]))
题目4 给定一组数,打印可以构造的所有表达式,数的顺序不能变,和题目2类似,差别就是顺序不能变
def all_exp(A, l, r):
if l == r: yield str(A[l])
else:
for pivot in xrange(l, r):
for left in all_exp(A, l, pivot):
for right in all_exp(A, pivot + 1, r):
for op in '+-*/':
yield '(' + left + op + right + ')'
分治法一般需要保存子问题的结果,这里用generaor