我正在尝试使用 Scala 解决最近的一个面试问题。
您有一个屏幕键盘,它是一个 6 行、每列 5 列的网格。从 A 到 Z 的字母和空格首先排列在网格行中。
您可以在屏幕键盘上使用它来输入单词。通过按向左、向右、向上、向下或 OK 键使用您的电视遥控器来输入每个字符。
问题:给定一个输入字符串,找出需要在遥控器上按下以键入输入的击键序列。
代码实现可以在
https://github.com/mradityagoyal/scala/blob/master/OnScrKb/src/main/scala/OnScrKB.scala
我试图用三种不同的方法来解决这个问题..
简单的 forldLeft。
def keystrokesByFL(input: String, startChar: Char = 'A'): String = { val zero = ("", startChar) //(acc, last) + next => (acc+ aToB , next) def op(zero: (String, Char), next: Char): (String, Char) = zero match { case (acc, last) => (acc + path(last, next), next) } val result = input.foldLeft(zero)(op) result._1
}
分而治之 - 使用分而治之的机制。该算法类似于归并排序。* 如果长度> 3,我们将输入单词一分为二 * 我们递归调用子程序以从拆分中获取左右两半的路径。*最后..我们添加第一个击键+从第一个字符串末尾到第二个字符串开头的击键+第二个击键。* 本质上,我们将输入字符串分成两个较小的部分,直到我们达到 4 的大小。对于小于 4,我们使用折叠权。
def keystrokesByDnQ(input: String, startChar: Char = 'A'): String = { def splitAndMerge(in: String, startChar: Char): String = { if (in.length() < 4) { //if length is <4 then dont split.. as you might end up with one side having only 1 char. keystrokesByFL(in, startChar) } else { //split val (x, y) = in.splitAt(in.length() / 2) splitAndMerge(x, startChar) + splitAndMerge(y, x.last) } } splitAndMerge(input, startChar)
}
折叠 - 使用底层操作是关联的(但不是可交换的)的属性。* 例如.. keystrokes("ABCDEFGHI", startChar = 'A') == keystrokes("ABC", startChar='A')+keystrokes("DEF", 'C') + keystrokes("GHI", 'F')
def keystrokesByF(input: String, startChar: Char = 'A'): String = { val mapped = input.map { x => PathAcc(text = "" + x, path = "") } // map each character in input to case class PathAcc("CharAsString", "") val z = PathAcc(text = ""+startChar, path = "") //the starting char. def op(left: PathAcc, right: PathAcc): PathAcc = { PathAcc(text = left.text + right.text, path = left.path + path(left.text.last, right.text.head) + right.path) } val foldresult = mapped.fold(z)(op) foldresult.path }
我的问题: 1. 分而治之的方法比折叠更好吗?
折叠和分而治之比 foldLeft 更好(针对这个特定问题)
有没有办法可以将分而治之的方法或折叠方法表示为 Monad?我可以看到结合律得到满足……但我无法弄清楚这里是否存在幺半群……如果是的话……它对我有什么好处?
分而治之的方法是解决这个特定问题的最佳方法吗?
哪种方法更适合火花?
欢迎任何建议..