【问题标题】:recursive function not recognizing initial input in scala递归函数无法识别scala中的初始输入
【发布时间】:2017-11-14 08:54:04
【问题描述】:

这是Scala 中的函数式编程中的一个练习。

实现 hasSubsequence for 检查一个 List 是否包含另一个 List 作为子序列。例如, List(1,2,3,4) 将具有 List(1,2)、List(2,3) 和 List(4) 作为 子序列等。

我的第一次尝试如下:

def go[A](l: List[A], sub:List[A]): Boolean =
(l, sub) match {
        case (_,Nil) => true
        case (Nil,_) => false
        case (a :: as, x :: xs) if a == x => go(as, xs)
        case (a :: as, _) => go(as, sub)
}                                                 //> go: [A](l: List[A], sub: List[A])Boolean
go(List(1,2,0), List(1,0))                        //> res6: Boolean = true

这是错误的,因为在递归中,初始 sub 输入没有被存储(或未被识别),而是在每次调用时被替换。

但是,如果我将该函数用作辅助函数

def hasSubsequence[A](l: List[A], sub: List[A]): Boolean ={
def go[A](l: List[A], a:List[A]): Boolean =
(l, a) match {
        case (_,Nil) => true
        case (Nil,_) => false
        case (a :: as, x :: xs) if a == x => go(as, xs)
        case (a :: as, _) => go(as, sub)
}
go(l,sub)
}                                                 //> hasSubsequence: [A](l: List[A], sub: List[A])Boolean
hasSubsequence(List(1,2,0), List(1,0))            //> res5: Boolean = false

然后它被存储为一个值并且工作正常。问题是,如果我不想要任何辅助函数,有没有办法做到这一点?

更新:每@jwvh 第二个需要更正如下。

def hasSubsequence[A](l: List[A], sub: List[A]): Boolean ={
    def go[A](l: List[A], a:List[A]): Boolean =
    (l, a) match {
            case (_,Nil) => true
            case (Nil,_) => false
            case (a :: as, x :: xs) if a == x => go(as, xs)
            case (a :: as, _) if a == sub.head => go(a::as, sub)
            case (a :: as, _) => go(as,sub)
    }
go(l,sub)
}                                                 //> hasSubsequence: [A](l: List[A], sub: List[A])Boolean
hasSubsequence(List(1,2,0), List(1,0))            //> res0: Boolean = false
hasSubsequence(List(1,1,2,0), List(1,2))          //> res1: Boolean = true

【问题讨论】:

  • 第三个参数?

标签: scala recursion pattern-matching


【解决方案1】:

您的第二个解决方案也不正确。

hasSubsequence(List(1,1,2,0), List(1,2))  // res0: Boolean = false

正如@Dima 所评论的,第三个参数将有助于跟踪我们是否已经开始了匹配序列。此外,如果匹配序列开始但失败,我们需要继续搜索。

def hasSubsequence[A]( l      : List[A]
                     , sub    : List[A]
                     , inMatch: Boolean = false ): Boolean =
  (l, sub) match {
    case (_,Nil) => true
    case (Nil,_) => false
    case (a :: as, x :: xs) if a == x =>
      hasSubsequence(as, xs, true) || hasSubsequence(as, sub)
    case _ =>
      !inMatch && hasSubsequence(l.tail, sub)
  }

这不是尾递归,而是没有辅助函数的递归。

hasSubsequence(List(1,2,0), List(1,0))    // res0: Boolean = false
hasSubsequence(List(1,2,0), List(1,2))    // res1: Boolean = true
hasSubsequence(List(1,2,0), List(2,0))    // res2: Boolean = true
hasSubsequence(List(1,1,2,0), List(2,1))  // res3: Boolean = false
hasSubsequence(List(1,1,2,0), List(1,2))  // res4: Boolean = true

【讨论】:

  • 谢谢@jwvh!请问这里尾递归有多重要?实际上,您会花额外的时间来确保您编写的函数是尾递归的吗?
  • 如果您的数据集非常大,建议使用尾递归。如果l 参数是一个非常 长的List,那么尾递归方法会更快一些并且不会引发堆栈溢出异常。
【解决方案2】:
def hasSubsequence[A](sup: List[A], sub: List[A]): Boolean = {
    def isPrefix(pref: List[A], xs: List[A]): Boolean = (pref,xs) match {
      case (Cons(h1,t1),Cons(h2,t2)) => h1 == h2 && isPrefix(t1,t2)
      case (Nil,_) => true
      case _ => false
    }

    sup match {
      case Cons(h, t) => isPrefix(sub,sup) || hasSubsequence(t,sub)
      case _ => false
    }
  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-23
    • 1970-01-01
    • 1970-01-01
    • 2019-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多