[LeetCode/Scala] 机器人的运动范围

题目

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:

输入:m = 2, n = 3, k = 1
输出:3
示例 1:

输入:m = 3, n = 1, k = 0
输出:1
提示:

1 <= n,m <= 100
0 <= k <= 20

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ji-qi-ren-de-yun-dong-fan-wei-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析

这题非常简单,只需要dfs去搜索,就可以在规定的时间内解决问题。
我们解决问题的过程函数化, 也就是把dfs的过程函数化。 我们对每一个点 p p p,寻找四个方向的邻居,并且去掉不符合的点。这里我们的条件是:

  1. 不能越界
  2. 坐标数位和小于 k k k

简单的表示就是:

p => neighbour(p) => filter not in Bound => filter bitSum>k

我们可以把判断条件写到dfs函数的内部。但是这样做,当我们修改的时候,需要修dfs主函数。更好的做法是将过滤条件作为参数传入主函数中。以下是我实现的一个版本。

case class Point(x:Int, y:Int){
    def +(that:Point):Point = Point(x + that.x, y + that.y)
    def -(that:Point):Point = Point(x - that.x, y - that.y)

}
object PointNei{
    val dir4 = List(Point(0,1), Point(0,-1), Point(1,0), Point(-1, 0))
    val dir8 = List(Point(-1,-1), Point(-1,1), Point(1,-1),Point(1,1)) ++ dir4
    
    def nei4(n:Int, m:Int)(p:Point):List[Point] =
        dir4 map(_+p) filter inBound(n,m)
    
    def nei8(n:Int, m:Int)(p:Point):List[Point] = 
        dir8 map(_+p) filter inBound(n,m)
    
    def inBound(n:Int,m:Int)(p:Point):Boolean = 
        p.x < n && p.y < m && p.x>=0 && p.y >=0 
}
object Solution {
    type T = Point=>Boolean
    type LP = List[Point]
    type P = Point
    val zero = Set.empty[P]
    def dfs(T:P=>LP,F:List[T])(l:LP, visited:Set[P] = zero):Int = l match {
        case Nil => visited.size
        case h::t =>
            if(visited.contains(h)) dfs(T,F)(t, visited)
            else dfs(T,F)(t ++ help(T(h),F), visited + h)
    }
    def help(l:LP, F:List[T]):LP = F match {
        case Nil => l
        case p::ps => help(l filter p, ps)
    }

    def lek(k:Int)(p:P):Boolean = 
        bitSum(p.x)+bitSum(p.y) <= k

    def bitSum(x:Int, acc:Int = 0):Int = 
        if(x == 0) acc else bitSum(x / 10, acc + (x%10))
    
    def movingCount(m: Int, n: Int, k: Int): Int = {
        dfs(PointNei.nei4(m,n) ,List(lek(k),PointNei.inBound(m,n)))(List(Point(0,0)))
    }
}

这里用到的语法主要是函数参数的写法,可以看更简洁的例子。
函数参数的定义:

type T = Int => Boolean // 一个Int映射成Boolean
type N = Int => _ 
// 一个传入参数是Int的函数, scala 会自行推断返回类型,
// 但是如果在递归调用,我们需要明确指出。
object Try0 {
  def inc(x:Int):Int = x+1
  def mul(x:Int):Int = x*x
  def p1(x:Int):Boolean = x>=0
  def p2(x:Int):Boolean = x<10
  def f0(l:List[Int], P:List[Int => Boolean]):List[Int] = P match {
    case Nil => l
    case p::ps => f0(l filter p, ps)
  }

  def main(args: Array[String]): Unit = {
    println(f0((-100 to 100).toList,List(p1,p2)))
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值