master
  1<<-DOC
  2Given a singly linked list of integers, determine whether or not it's a palindrome.
  3
  4Example
  5
  6For l = [0, 1, 0], the output should be
  7isListPalindrome(l) = true;
  8For l = [1, 2, 2, 3], the output should be
  9isListPalindrome(l) = false.
 10Input/Output
 11
 12[time limit] 4000ms (rb)
 13[input] linkedlist.integer l
 14
 15A singly linked list of integers.
 16
 17Guaranteed constraints:
 180  list size  5 · 10^5,
 19-10^9  element value  10^9.
 20
 21[output] boolean
 22
 23Return true if l is a palindrome, otherwise return false.
 24DOC
 25
 26describe "is_list_palindrome" do
 27  def palindrome?(head)
 28    return true if head.nil?
 29
 30    length = length_of(head)
 31    mid = length.even? ? length / 2 : (length / 2) + 1
 32    distance_travelled = 0
 33    left_sum, right_sum = 0, 0
 34
 35    node = head
 36    until node.nil?
 37      if distance_travelled >= mid
 38        right_sum += node.value
 39      else
 40        left_sum += node.value
 41      end
 42      distance_travelled += 1
 43      node = node.next
 44    end
 45
 46    if length.even?
 47      left_sum - right_sum == 0
 48    else
 49      left_sum - right_sum == 1
 50    end
 51  end
 52
 53  def length_of(head)
 54    n = 1
 55    n += 1 while head = head.next
 56    n
 57  end
 58
 59  # recursion blows the stack for a long list
 60  #def advance_to(head, index)
 61    #return head if index == 0
 62    #advance_to(head.next, index - 1)
 63  #end
 64
 65  def advance_to(head, index)
 66    return head if index == 0
 67    (index - 1).downto(0) do |n|
 68      head = head.next
 69    end
 70    head
 71  end
 72
 73  def reverse(head)
 74    new_root = nil
 75    root = head
 76
 77    while root
 78      next_node = root.next
 79      root.next = new_root
 80      new_root = root
 81      root = next_node
 82    end
 83    new_root
 84  end
 85
 86  def palindrome?(head)
 87    return true if head.nil?
 88    length = length_of(head)
 89    mid = length / 2
 90
 91    x, y = head, reverse(advance_to(head, mid))
 92    0.upto(mid - 1) do |i|
 93      return false unless x.value == y.value
 94      x, y = x.next, y.next
 95    end
 96    true
 97  end
 98
 99  class ListNode
100    attr_accessor :value, :next
101
102    def initialize(value, next_node: nil)
103      @value = value
104      @next = next_node
105    end
106
107    def to_a
108      result = []
109      current = self
110      until current.nil?
111        result.push(current.value)
112        current = current.next
113      end
114      result
115    end
116  end
117
118  def to_list(items)
119    x = nil
120    items.inject(nil) do |memo, item|
121      node = ListNode.new(item)
122      if memo.nil?
123        x = node
124      else
125        memo.next = node
126      end
127      node
128    end
129    x
130  end
131
132  [
133    { l: [0, 1, 0], x: true },
134    { l: [1, 2, 2, 3], x: false },
135    { l: [1, 1000000000, -1000000000, -1000000000, 1000000000, 1], x: true },
136    { l: [1, 2, 3, 3, 2], x: false },
137    { l: [1, 2, 3, 1, 2, 3], x: false },
138    { l: [], x: true },
139    { l: [3, 5, 3, 5], x: false },
140    { l: [1, 5, 2, 4], x: false },
141    { l: [10], x: true },
142    { l: [0, 0], x: true },
143    { l: [1, 3, 2, 2, 2], x: false },
144  ].each do |x|
145    it do
146      expect(palindrome?(to_list(x[:l]))).to eql(x[:x])
147    end
148  end
149end