我得解法只是簡單的暴力求解,嘗試每一種可能性,把符合條件的結果找出來。應該是有更加高效的算法,至少能夠用到剪枝;僅僅是暴力求解,彷佛沒有拿來作得理由,主要是爲了用scala嘗試functional的解法,經過構建基礎的組件(函數),將它們組合,最後獲得結果;算法
完整的代碼以下:express
object App extends App { abstract trait Op { def value: Int def expression: String def isValid: Boolean } object Op { def list(x: Op, y: Op) = List(Add(x, y), Sub(x, y), Mul(x, y), Div(x, y)) } case class Add(left: Op, right: Op) extends Op { override def value: Int = left.value + right.value override def expression: String = "(" + left.expression + " + " + right.expression + ")" override def isValid: Boolean = left.value <= right.value } case class Sub(left: Op, right: Op) extends Op { override def value: Int = left.value - right.value override def expression: String = "(" + left.expression + " - " + right.expression + ")" override def isValid: Boolean = left.value > right.value } case class Mul(left: Op, right: Op) extends Op { override def value: Int = left.value * right.value override def expression: String = left.expression + " * " + right.expression override def isValid: Boolean = left.value <= right.value && left.value != 1 && right.value != 1 } case class Div(left: Op, right: Op) extends Op { override def value: Int = left.value / right.value override def expression: String = left.expression + " / " + right.expression override def isValid: Boolean = right.value != 0 && left.value % right.value == 0 && right.value != 1 } case class Val(override val value: Int) extends Op { override def expression: String = s"$value" override def isValid: Boolean = true } def splitArray(array: List[Int]): List[(List[Int], List[Int])] = array match { case Nil => throw new RuntimeException("no empty array allowed here.") case x :: y :: Nil => List((List(x), List(y))) case h :: tail => (List(h), tail) :: (for { (x, y) <- splitArray(tail) } yield (h :: x, y)) } def express(nums: List[Int]): List[Op] = nums match { case Nil => throw new RuntimeException("empty list") case x :: Nil => List(Val(x)) case _ => for { (left, right) <- splitArray(nums) x <- express(left) y <- express(right) op <- Op.list(x, y) if op.isValid } yield op } def choices(nums: List[Int]): List[List[Int]] = { def go(lists: List[List[Int]], i: Int, used: Set[Int]): List[List[Int]] = if (i == nums.length) lists else { for { x <- nums if (!used(x)) subChoice <- go(lists ++ lists.map(x :: _), i + 1, used + x) } yield { subChoice } } go(List(Nil), 0, Set.empty).toSet.toList } def countDown(nums: Array[Int], res: Int): List[Op] = { for { list <- choices(nums.toList) if (!list.isEmpty) op <- express(list) if (op.value == res) } yield op } choices(Array(1, 3, 10).toList).foreach(println) // splitArray(Array(1, 3, 7, 10, 25, 50).toList).foreach(println) val opList = countDown(Array(1, 3, 7, 10, 25, 50), 765) opList.foreach(op => println(op.expression)) }
1. 之因此使用Op trait,主要有兩個做用,a. 咱們不單單是關心最後的值,是否等於765,也關心這個表達式自己;2. 判斷這個表達式是否有效,計算出的結果是不是整數;ide
2. choices(list), 返回用list元素的全部可能的組合,好比choicee(list(1, 2)) => [], [1], [2], [1, 2], [2, 1];接下來能夠用每一個組合去求出Op。 這個方法的時間複雜度即爲n!, 因此能夠看出這個算法只能是玩玩而已;函數
3. 而後用上面求出的組合,去計算表達式,a. 要過濾掉過的集合,由於咱們沒有用來表示空的Op,b. 對於只有一個元素的集合,只有一種可能性,就是該元素自己, Val(x); c. 當有多個元素的時候,須要把該集合切分紅兩邊,遞歸計算Op,而後把Op合併;scala
Just For Fun.code