Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 链表链接的Scala尾部递归解法_Algorithm_Scala_Linked List_Tail Recursion - Fatal编程技术网

Algorithm 链表链接的Scala尾部递归解法

Algorithm 链表链接的Scala尾部递归解法,algorithm,scala,linked-list,tail-recursion,Algorithm,Scala,Linked List,Tail Recursion,我想为Leetcode上的以下问题编写一个尾部递归解决方案- 给您两个非空链表,表示两个非负整数。数字按相反顺序存储,每个节点包含一个数字。将这两个数字相加,并将其作为链表返回 您可以假设这两个数字不包含任何前导零,除了数字0本身 例如: 在最后一行中,我无法找到调用递归函数的方法。 我在这里试图实现的是对add函数的递归调用,该函数使用进位将两个列表的头相加,并返回一个节点。返回的节点与调用堆栈中的节点链接 我是scala的新手,我猜我可能错过了一些有用的构造 /** * Definiti

我想为Leetcode上的以下问题编写一个尾部递归解决方案-

给您两个非空链表,表示两个非负整数。数字按相反顺序存储,每个节点包含一个数字。将这两个数字相加,并将其作为链表返回

您可以假设这两个数字不包含任何前导零,除了数字0本身

例如:

在最后一行中,我无法找到调用递归函数的方法。 我在这里试图实现的是对add函数的递归调用,该函数使用进位将两个列表的头相加,并返回一个节点。返回的节点与调用堆栈中的节点链接

我是scala的新手,我猜我可能错过了一些有用的构造

/**
 * Definition for singly-linked list.
 * class ListNode(_x: Int = 0, _next: ListNode = null) {
 *   var next: ListNode = _next
 *   var x: Int = _x
 * }
 */
import scala.annotation.tailrec
object Solution {
  def addTwoNumbers(l1: ListNode, l2: ListNode): ListNode = {
    add(l1, l2, 0)
  }
  //@tailrec
  def add(l1: ListNode, l2: ListNode, carry: Int): ListNode = {
    var sum = 0;
    sum = (if(l1!=null) l1.x else 0) + (if(l2!=null) l2.x else 0) + carry;
    if(l1 != null || l2 != null || sum > 0)
      ListNode(sum%10,add(if(l1!=null) l1.next else null, if(l2!=null) l2.next else null,sum/10))
    else null;
  }
}

您有几个问题,这些问题大部分可以归结为不习惯用语

var
null
这样的事情在Scala中并不常见,通常,您会使用尾部递归算法来避免这类事情

最后,请记住,尾部递归算法要求最后一个表达式是普通值或递归调用。为此,您通常会跟踪剩余的作业以及累加器

以下是一个可能的解决方案:

type Digit = Int // Refined [0..9]
type Number = List[Digit] // Refined NonEmpty.

def sum(n1: Number, n2: Number): Number = {
  def aux(d1: Digit, d2: Digit, carry: Digit): (Digit, Digit) = {
    val tmp = d1 + d2 + carry
    val d = tmp % 10
    val c = tmp / 10
    
    d -> c
  }

  @annotation.tailrec
  def loop(r1: Number, r2: Number, acc: Number, carry: Digit): Number =
    (r1, r2) match {
      case (d1 :: tail1, d2 :: tail2) =>
        val (d, c) = aux(d1, d2, carry)
        loop(r1 = tail1, r2 = tail2, d :: acc, carry = c)

      case (Nil, d2 :: tail2) =>
        val (d, c) = aux(d1 = 0, d2, carry)
        loop(r1 = Nil, r2 = tail2, d :: acc, carry = c)

      case (d1 :: tail1, Nil) =>
        val (d, c) = aux(d1, d2 = 0, carry)
        loop(r1 = tail1, r2 = Nil, d :: acc, carry = c)

      case (Nil, Nil) =>
        acc
    }

  loop(r1 = n1, r2 = n2, acc = List.empty, carry = 0).reverse
}
现在,这种递归往往非常冗长。
通常,stdlib提供了使相同算法更简洁的方法:

// This is a solution that do not require the numbers to be already reversed and the output is also in the correct order.
def sum(n1: Number, n2: Number): Number = {
  val (result, carry) = n1.reverseIterator.zipAll(n2.reverseIterator, 0, 0).foldLeft(List.empty[Digit] -> 0) {
    case ((acc, carry), (d1, d2)) =>
      val tmp = d1 + d2 + carry
      val d = tmp % 10
      val c = tmp / 10
      (d :: acc) -> c
  }


  if (carry > 0) carry :: result else result
}

Scala在LeetCode上不太受欢迎,但这种解决方案(不是最好的)会被LeetCode的在线评委接受:

import scala.collection.mutable._
object Solution {
    def addTwoNumbers(listA: ListNode, listB: ListNode): ListNode = {
        var tempBufferA: ListBuffer[Int] = ListBuffer.empty
        var tempBufferB: ListBuffer[Int] = ListBuffer.empty
        tempBufferA.clear()
        tempBufferB.clear()

        def listTraversalA(listA: ListNode): ListBuffer[Int] = {
            if (listA == null) {
                return tempBufferA

            } else {
                tempBufferA += listA.x
                listTraversalA(listA.next)
            }
        }

        def listTraversalB(listB: ListNode): ListBuffer[Int] = {
            if (listB == null) {
                return tempBufferB

            } else {
                tempBufferB += listB.x
                listTraversalB(listB.next)
            }
        }
        val resultA: ListBuffer[Int] = listTraversalA(listA)
        val resultB: ListBuffer[Int] = listTraversalB(listB)
        val resultSum: BigInt = BigInt(resultA.reverse.mkString) + BigInt(resultB.reverse.mkString)
        var listNodeResult: ListBuffer[ListNode] = ListBuffer.empty
        val resultList = resultSum.toString.toList
        var lastListNode: ListNode = null

        for (i <-0 until resultList.size) {
            if (i == 0) {
                lastListNode = new ListNode(resultList(i).toString.toInt)
                listNodeResult += lastListNode

            } else {
                lastListNode = new ListNode(resultList(i).toString.toInt, lastListNode)
                listNodeResult += lastListNode
            }
        }

        return listNodeResult.reverse(0)
    }
}
导入scala.collection.mutable_
对象解{
def AddTwoNumber(listA:ListNode,listB:ListNode):ListNode={
var tempBufferA:ListBuffer[Int]=ListBuffer.empty
var tempBufferB:ListBuffer[Int]=ListBuffer.empty
tempBufferA.clear()
tempBufferB.clear()
def listTraversalA(listA:ListNode):ListBuffer[Int]={
if(listA==null){
返回临时缓冲区
}否则{
tempBufferA+=listA.x
listTraversalA(listA.next)
}
}
def listTraversalB(listB:ListNode):ListBuffer[Int]={
if(listB==null){
返回临时缓冲区
}否则{
tempBufferB+=listB.x
listTraversalB(listB.next)
}
}
val结果:ListBuffer[Int]=listTraversalA(listA)
val resultB:ListBuffer[Int]=listTraversalB(listB)
val resultSum:BigInt=BigInt(resultA.reverse.mkString)+BigInt(resultB.reverse.mkString)
变量listNodeResult:ListBuffer[ListNode]=ListBuffer.empty
val resultList=resultSum.toString.toList
var lastListNode:ListNode=null

对于(如果我面试某人,他们给我这个解决方案,他们会立即放弃。是的,我的不会通过,因为我使用的是Scala内置数据结构,而不是
ListNode
。我想澄清的是,这本身并不是一个糟糕的解决方案,它对Scala来说是一个糟糕的解决方案。事实上,正如我在e其他评论,就我在几个问题中所看到的,Leetcode和Scala并不赞同。顺便说一句,Leetcode似乎并不适合Scala,他们使用的数据结构都在stdlib中(比如这个节点列表),他们的大多数问题都希望以一种强制方式解决(这在Scala中不是标准).如果您的最终目标是学习Scala,则使用或可能会更好。
import scala.collection.mutable._
object Solution {
    def addTwoNumbers(listA: ListNode, listB: ListNode): ListNode = {
        var tempBufferA: ListBuffer[Int] = ListBuffer.empty
        var tempBufferB: ListBuffer[Int] = ListBuffer.empty
        tempBufferA.clear()
        tempBufferB.clear()

        def listTraversalA(listA: ListNode): ListBuffer[Int] = {
            if (listA == null) {
                return tempBufferA

            } else {
                tempBufferA += listA.x
                listTraversalA(listA.next)
            }
        }

        def listTraversalB(listB: ListNode): ListBuffer[Int] = {
            if (listB == null) {
                return tempBufferB

            } else {
                tempBufferB += listB.x
                listTraversalB(listB.next)
            }
        }
        val resultA: ListBuffer[Int] = listTraversalA(listA)
        val resultB: ListBuffer[Int] = listTraversalB(listB)
        val resultSum: BigInt = BigInt(resultA.reverse.mkString) + BigInt(resultB.reverse.mkString)
        var listNodeResult: ListBuffer[ListNode] = ListBuffer.empty
        val resultList = resultSum.toString.toList
        var lastListNode: ListNode = null

        for (i <-0 until resultList.size) {
            if (i == 0) {
                lastListNode = new ListNode(resultList(i).toString.toInt)
                listNodeResult += lastListNode

            } else {
                lastListNode = new ListNode(resultList(i).toString.toInt, lastListNode)
                listNodeResult += lastListNode
            }
        }

        return listNodeResult.reverse(0)
    }
}