プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問をやる。今回は、Q13:覆面算を満たすのは何通り?。

Q: “READ+WRITE+TALK=SKILL”という文字列が与えられた時、式を満たす文字と数の組み合わせは何通りあるか?ただし、項の最上位に0は入らず、同じ文字には同じ数、異なる文字には異なる数が入る。

性能は良くない。 けど、左辺が単項 or 複数項の足し算、右辺の単項であれば、他の文字列でも可。

def count(str:String) = {
  val Array(left, right) = str.split("=",2)
  val expressions = left.split("[+]")
  val characters = (expressions.flatten ++ right).distinct
  val initials = right.head +: expressions.map(_.head)

  (0 to 9).permutations.count{ com =>
    val mapping = characters.zip(com).toMap
    mapping.forall { case (char, num) =>
      if(num == 0 && initials.contains(char))  false else true
    } &&
    expressions.foldLeft(0){ (z, expr) =>
      z + expr.reverse.zipWithIndex.foldLeft(0){ (zz, n) =>
        zz + (mapping(n._1) * scala.math.pow(10, n._2).toInt)
      }
    } == right.reverse.zipWithIndex.foldLeft(0){(zzz, n) =>
      zzz + mapping(n._1) * scala.math.pow(10, n._2).toInt
    }
  }
}

count("READ+WRITE+TALK=SKILL")