无法在 Ruby 中正确格式化 "Add Two Numbers" 输出(单链表)

Can't format "Add Two Numbers" output correctly in Ruby (Singly Linked List)

试图在 Ruby (https://leetcode.com/problems/add-two-numbers/) 中解决 leetcode 的 "Add Two Numbers" 问题。我知道我根本没有解决问题,只是想确保我可以先以正确的 "ListNode" 格式获得输出。我试图添加的 ListNode 一直在写自己,因为它在 while 循环中,但我一直在研究这个,无法弄清楚如何按照 leetcode 想要的方式获取输出。

感谢任何帮助!

这是我的代码:

# class ListNode
#     attr_accessor :val, :next
#     def initialize(val = 0)
#         @val = val
#         @next = nil
#     end
# end

# @param {ListNode} l1
# @param {ListNode} l2
# @return {ListNode}

def add_two_numbers(l1, l2)
    current_output = head = ListNode.new()
    while l1.next != nil
        sum = l1.val + l2.val
        if current_output.next != nil
            current_output = current_output.next
        else
            current_output.next = ListNode.new(sum)
            current_output.next = current_output.next.next
        end

        l1.val = l1.next.val
        l1.next = l1.next.next
        l2.val = l2.next.val
        l2.next = l2.next.next
    end
    last_sum = l1.val + l2.val
    #current_output.next = ListNode.new(last_sum)
    return current_output 
end

注意:它要求输出是一个 ListNode 对象,所以我不能创建自己的 LinkedList class

这是一个对两个链表求和的代码,然后我将把它分解,这样你就可以参与其中并使用它们,但是它没有经过很好的测试,因为我是在入侵 [=27 之后才写的=] 博客 post 并对其进行少量编辑:

class Node
  attr_accessor :value, :next

  def initialize(value, next_node)
      @value = value
      @next = next_node
  end
end


class LinkedList
  include Enumerable
  def initialize
    @head = nil
  end

  def add_to_list(value)
    return @head = Node.new(value, nil) unless @head
    current_node = @head
    while current_node.next != nil
      current_node = current_node.next
    end
    current_node.next = Node.new(value, nil)
  end

  def each
    current = @head
    while current
      yield current.value
      current = current.next
    end
  end

  def to_i
    self.reduce(""){ |s, l| "#{l}#{s}" }.to_i
  end
end


list1 = LinkedList.new
list2 = LinkedList.new
sum = LinkedList.new

list1.add_to_list(2)  # => #<Node:0x000055951cb54940 @value=2, @next=nil>
list1.add_to_list(4)  # => #<Node:0x000055951cb545f8 @value=4, @next=nil>
list1.add_to_list(3)  # => #<Node:0x000055951cb543a0 @value=3, @next=nil>

list2.add_to_list(5)  # => #<Node:0x000055951cb54170 @value=5, @next=nil>
list2.add_to_list(6)  # => #<Node:0x000055951cb7bf40 @value=6, @next=nil>
list2.add_to_list(4)  # => #<Node:0x000055951cb7bd10 @value=4, @next=nil>

result = list1.to_i + list2.to_i  # => 807
result.digits.each do |i|
  sum.add_to_list(i)
end
puts list1.to_i  # => nil
puts list2.to_i  # => nil
puts sum.to_i  # => nil

# >> 342
# >> 465
# >> 807

上面代码中下面是链表节点的定义:

class Node
  attr_accessor :value, :next

  def initialize(value, next_node)
      @value = value
      @next = next_node
  end
end

该节点有一个值属性和一个指向链表中它后面的节点的指针。

在这种情况下,让我们分解一下只有两个方法的链表: 第一个是 add_to_list:

  def add_to_list(value)
    return @head = Node.new(value, nil) unless @head
    current_node = @head
    while current_node.next != nil
      current_node = current_node.next
    end
    current_node.next = Node.new(value, nil)
  end

它接受一个整数作为值,然后在链表中为它创建一个节点。

第二种方法是to_i,它将链表backward转换为一个整数,所以稍后我们可以做list1.to_i + list2.to_i,它给出了两个列表的总和:

  def each
    current = @head
    while current
      yield current.value
      current = current.next
    end
  end

  def to_i
    self.reduce(""){ |s, l| "#{l}#{s}" }.to_i
  end

现在让我们来看看进行实际计算的代码:

  • 这里是list1, list2, and the sum lists的初始化:
list1 = LinkedList.new
list2 = LinkedList.new
sum = LinkedList.new

list1.add_to_list(2)  # => #<Node:0x000055951cb54940 @value=2, @next=nil>
list1.add_to_list(4)  # => #<Node:0x000055951cb545f8 @value=4, @next=nil>
list1.add_to_list(3)  # => #<Node:0x000055951cb543a0 @value=3, @next=nil>

list2.add_to_list(5)  # => #<Node:0x000055951cb54170 @value=5, @next=nil>
list2.add_to_list(6)  # => #<Node:0x000055951cb7bf40 @value=6, @next=nil>
list2.add_to_list(4)  # => #<Node:0x000055951cb7bd10 @value=4, @next=nil>
  • 这里是 list1, and list2:
  • 的实际总和
result = list1.to_i + list2.to_i  # => 807

  • 这里是result整数值到链表的转换:
result.digits.each do |i|
  sum.add_to_list(i)
end
  • 这里是打印出来的list1, list2, and sum个变量的内容:
puts list1.to_i  # => nil
puts list2.to_i  # => nil
puts sum.to_i  # => nil

# >> 342
# >> 465
# >> 807

所以在你的 add_two_numbers 问题方法中,你想要的只是以正确的方式将两个链表转换为整数,然后求和,然后将得到的整数转换为链表列出将作为最终解决方案返回的列表,并确保 运行 足够的测试用例并测试角落用例。

经典解法

def add_two_numbers(l1, l2)
  head = ListNode.new
  carry = 0
  curr = head

  until l1.nil? && l2.nil? && carry.zero?
    v1 = l1&.val || 0
    v2 = l2&.val || 0
    carry, digit = (v1 + v2 + carry).divmod(10)
    curr.next = ListNode.new(digit)
    curr = curr.next
    l1 = l1&.next
    l2 = l2&.next
  end

  head.next
end

注意l1l2可能有不同的长度,所以你应该在两个节点都变成nil时结束循环。

如果你不知道语法 obj&.mthd,它被称为 "safe navigation",这意味着如果 objnil,return nil 立即调用 mthd 。如果 obj 不是 nil,return 无论如何 obj.mthd returns.

作弊

您可以算出每个列表代表的整数,将它们相加,并根据总和构建结果列表。

# Monkey-patch ListNode
# to make a list enumerable,
# so that we can call `reduce` on it.
ListNode.class_eval do
  include Enumerable

  def each(&block)
    return enum_for(:each) unless block
    block.(@val)
    @next.each(&block) if @next
  end
end

def add_two_numbers(l1, l2)
  n1 = l1.reduce(""){|s, n| "#{n}#{s}"}.to_i
  n2 = l2.reduce(""){|s, n| "#{n}#{s}"}.to_i

  head = ListNode.new
  (n1 + n2).digits.reduce(head) do |prev_node, digit|
    ListNode.new(digit).tap{|node| prev_node.next = node}
  end

  head.next
end