Premiumlab  

https://leetcode.com/problems/palindrome-linked-list/#/description

 

Given a singly linked list, determine if it is a palindrome.

Follow up:
Could you do it in O(n) time and O(1) space?

 

 

Hint: 

Two pointer + reverse 

 

 

Sol:

 

Time complexity O(n), Space complexity O(n):

 

Use the fast and slow pointers to find the mid point. Fast pointer moves two moves when slow pointer makes one move. Use stack to record every move the slow pointer moves. When the fast pointer reaches the end, the slow pointer is at the mid point and the first half of the linked list is already in the stack. Then the slow pointer moves on, and compares its value with stack top.

 

 

Time complexity O(n), Space complexity O(1):

 

Find the mid point first and reverse the second half, then compare the first half and the reversed sencond half.

 

The following codes in space O(1). 

 

 

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def isPalindrome(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        # two pointer technique
        fast = slow = head
        #find the mid node
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
        # reverse the second half, i.e.reverse slow and node
        node = None
        while slow:
            # make a copy of slow.next before overwrite it
            # nxt = slow.next, in this prob we do not need to this
            # reverse slow and slow.next
            tmp = slow.next
            slow.next = node
            # go forward 
            node = slow
            slow = tmp
        # comapre the first and second half nodes
        while node:
            if node.val != head.val:
                return False
            node = node.next
            head = head.next
        return True

 

 

Note:

 

1 The fast pointer moves two steps while the slow pointer moves one step at a step, and when the fast pointer stops, the slow pointer is at mid point. Bingo!

 

2 Q: How to reverse a linked list ?

 

 

A:

 

 

 

 

Step 1: use a tmp varibale to store the next link of current node before overwrite it

 

tmp = cur.next

 

Step2 : reverse, let the next link of current node point to the previous node

 

cur.next = pre

 

Step 3: Advance

 

pre = cur

cur = tmp

 

class ListNode:
    def __init__(self,x):
        self.val = x
        self.next = None

        
def reverseLinkedList(head):
    if head is None or head.next is None:
        return head
    pre = None
    cur = head
    h = head
    while cur:
        h = cur
        tmp = cur.next
        cur.next = pre
        pre = cur
        cur = tmp
    return h
        

 

http://blog.csdn.net/u011608357/article/details/36933337

 

 

P.S. Do not dig too deep. ugh.

 

 

 

 

 

 

 

Similar problem:

https://github.com/Premiumlab/Python-for-Algorithms--Data-Structures--and-Interviews/blob/master/Linked%20Lists/Linked%20Lists%20Interview%20Problems/Linked%20List%20Interview%20Problems%20-%20SOLUTIONS/Singly%20Linked%20List%20Cycle%20Check%20-%20SOLUTION.ipynb

 

 

Singly Linked List Cycle Check - SOLUTION

Problem

Given a singly linked list, write a function which takes in the first node in a singly linked list and returns a boolean indicating if the linked list contains a "cycle".

A cycle is when a node's next point actually points back to a previous node in the list. This is also sometimes known as a circularly linked list.

You've been given the Linked List Node class code:

In [1]:
class Node(object):
    
    def __init__(self,value):
        
        self.value = value
        self.nextnode = None
 

Solution

To solve this problem we will have two markers traversing through the list. marker1 and marker2. We will have both makers begin at the first node of the list and traverse through the linked list. However the second marker, marker2, will move two nodes ahead for every one node that marker1 moves.

By this logic we can imagine that the markers are "racing" through the linked list, with marker2 moving faster. If the linked list has a cylce and is circularly connected we will have the analogy of a track, in this case the marker2 will eventually be "lapping" the marker1 and they will equal each other.

If the linked list has no cycle, then marker2 should be able to continue on until the very end, never equaling the first marker.

Let's see this logic coded out:

 
def cycle_check(node):

    # Begin both markers at the first node
    marker1 = node
    marker2 = node

    # Go until end of list
    while marker2 != None and marker2.nextnode != None:
        
        # Note
        marker1 = marker1.nextnode
        marker2 = marker2.nextnode.nextnode

        # Check if the markers have matched
        if marker2 == marker1:
            return True

    # Case where marker ahead reaches the end of the list
    return False

 

 

Test Your Solution

In [9]:
"""
RUN THIS CELL TO TEST YOUR SOLUTION
"""
from nose.tools import assert_equal

# CREATE CYCLE LIST
a = Node(1)
b = Node(2)
c = Node(3)

a.nextnode = b
b.nextnode = c
c.nextnode = a # Cycle Here!


# CREATE NON CYCLE LIST
x = Node(1)
y = Node(2)
z = Node(3)

x.nextnode = y
y.nextnode = z


#############
class TestCycleCheck(object):
    
    def test(self,sol):
        assert_equal(sol(a),True)
        assert_equal(sol(x),False)
        
        print "ALL TEST CASES PASSED"
        
# Run Tests

t = TestCycleCheck()
t.test(cycle_check)
 
ALL TEST CASES PASSED
 

Good Job!

 

posted on 2017-06-07 15:30  Premiumlab  阅读(167)  评论(0编辑  收藏  举报