已知一个 NxN 的国际象棋棋盘,棋盘的行号和列号都是从 0 开始。即最左上角的格子记为 (0, 0),最右下角的记为 (N-1, N-1)。
现有一个 “马”(也译作 “骑士”)位于 (r, c) ,并打算进行 K 次移动。
如下图所示,国际象棋的 “马” 每一步先沿水平或垂直方向移动 2 个格子,然后向与之相垂直的方向再移动 1 个格子,共有 8 个可选的位置。
现在 “马” 每一步都从可选的位置(包括棋盘外部的)中独立随机地选择一个进行移动,直到移动了 K 次或跳到了棋盘外面。
求移动结束后,“马” 仍留在棋盘上的概率。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/knight-probability-in-chessboard
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目是很简单的,只需要模拟点的映射过程。
即点(x,y, prob) => {(xk,yk, prob / 8 )} (k = 0 ~ 7)
之后做flatten。// 这一步的过程是flatMap
由于每次一个点变成8个点,那么点的数量是指数级的,k较大的时候内存会溢出。
所以,我们需要合并相同点的概率,即(x,y, p1) 和(x,y,p2) => (x,y, p1+ p2)。// group后对概率进行累加
每一次我们得到点如果越界,我们可以直接丢弃// 即filter过程。
所以,总的来说这道题很好的结合了,flatMap,groupby,filter的使用。
代码就很简单了
object Solution {
def knightProbability(N: Int, K: Int, r: Int, c: Int): Double = {
def f(l:List[(Int, Int, Double)],k:Int):Double =
if(k == 0) l.map{case ( x, y, z) => z}.sum else
f(
l
.flatMap {case (x, y, z) =>
List((x+2, y+1, z/8), (x+2, y-1, z/8), (x-2, y+1, z/8), (x-2, y-1, z /8),
(x+1, y+2, z/8), (x+1, y-2, z/8), (x-1, y-2, z/8), (x-1, y+2, z /8))}
.groupBy {case (x, y, z) => (x, y)}
.toList
.map{case (k, v) => (k._1, k._2, v.map(_._3).sum)}
.filterNot{case (x, y, z) => x < 0 || y < 0 || x >= N || y >= N},
k-1
)
f(List((r,c,1)), K)
}
}