【发布时间】:2010-09-23 19:43:49
【问题描述】:
给定n 整数,是否有O(n) 或O(n log n) 算法可以计算通过插入运算符-、+、* 和给定数字之间的括号?假设运算符只有二元变体,所以没有一元减号,除非需要在第一个元素之前。
例如,给定-3 -4 5,我们可以构建表达式(-3) * (-4) * 5,其值为60,是可能的最大值。
背景:
前段时间我在研究遗传算法时偶然发现了这个问题,并了解到可以使用经典的遗传算法非常简单地解决这个问题。然而,这运行缓慢,而且理论上很简单,因为代码在实践中变得相当丑陋(评估表达式,检查括号的正确位置等)。更重要的是,我们也不能保证找到绝对最大值。
遗传算法的所有这些缺点让我想知道:既然我们不必担心除法,有没有一种更经典的方法可以有效地做到这一点,例如动态规划或贪婪策略?
更新:
这是一个 F# 程序,它实现了@Keith Randall 提出的 DP 解决方案以及我在他的帖子的评论中所写的改进。这是非常低效的,但我坚持认为它是多项式并且具有三次复杂性。它在几秒钟内运行约 50 个元素数组。如果以完全命令式的方式编写可能会更快,因为很多时间可能浪费在构建和遍历列表上。
open System
open System.IO
open System.Collections.Generic
let Solve (arr : int array) =
let memo = new Dictionary<int * int * int, int>()
let rec Inner st dr last =
if st = dr then
arr.[st]
else
if memo.ContainsKey(st, dr, last) then
memo.Item(st, dr, last)
else
match last with
| 0 -> memo.Add((st, dr, last),
[
for i in [st .. dr - 1] do
for j in 0 .. 2 do
for k in 0 .. 2 do
yield (Inner st i j) * (Inner (i + 1) dr k)
] |> List.max)
memo.Item(st, dr, last)
| 1 -> memo.Add((st, dr, last),
[
for i in [st .. dr - 1] do
for j in 0 .. 2 do
for k in 0 .. 2 do
yield (Inner st i j) + (Inner (i + 1) dr k)
] |> List.max)
memo.Item(st, dr, last)
| 2 -> memo.Add((st, dr, last),
[
for i in [st .. dr - 1] do
for j in 0 .. 2 do
for k in 0 .. 2 do
yield (Inner st i j) - (Inner (i + 1) dr k)
] |> List.max)
memo.Item(st, dr, last)
let noFirst = [ for i in 0 .. 2 do yield Inner 0 (arr.Length - 1) i ] |> List.max
arr.[0] <- -1 * arr.[0]
memo.Clear()
let yesFirst = [ for i in 0 .. 2 do yield Inner 0 (arr.Length - 1) i ] |> List.max
[noFirst; yesFirst] |> List.max
let _ =
printfn "%d" <| Solve [|-10; 10; -10|]
printfn "%d" <| Solve [|2; -2; -1|]
printfn "%d" <| Solve [|-5; -3; -2; 0; 1; -1; -1; 6|]
printfn "%d" <| Solve [|-5; -3; -2; 0; 1; -1; -1; 6; -5; -3; -2; 0; 1; -1; -1; 6; -5; -3; -2; 0; 1; -1; -1; 6; -5; -3; -2; 0; 1; -1; -1; 6; -5; -3; -2; 0; 1; -1; -1; 6; -5; -3; -2; 0; 1; -1; -1; 6;|]
结果:
1000
6
540
2147376354
最后一个很可能是由于溢出而导致的错误,我只是想证明一个相对较大的测试运行速度太快而无法成指数。
【问题讨论】:
-
最初的想法 - 加法/减法似乎很少用于解决方案 - 乘法将是主要使用的运算符,+ / - 用于处理输入集中的 1(如 * 1 是没用的!),并应对您有奇数个负值的情况 - 简单的所有值相乘将导致 -ve。
标签: algorithm optimization f#