我正在尝试使用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
}
分而治之 - 使用分而治之的机制。该算法类似于合并排序。 *如果长度> 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)
}
折叠 - 使用基础操作关联的属性(但不是可交换的)。 *例如..键击(“ABCDEFGHI”,startChar ='A')==击键(“ABC”,startChar ='A')+击键(“DEF”,'C')+击键(“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?我可以看到相关法律得到满足......但是我无法弄清楚这里是否存在幺半群......如果是的话......它对我有什么影响?
分裂和征服是否是针对此特定问题的最佳方法?
哪种方法更适合火花?
欢迎提出任何建议。