题目

设计一种方式检查一个链表是否为回文链表。

样例

1->2->1 就是一个回文链表。

挑战

O(n)的时间和O(1)的额外空间。

解题

法一:

再定义一个链表,存放链表反转的值,再以此比较两个链表中的值是否相等,时间复杂度O(N),空间复杂度O(N)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param head a ListNode
     * @return a boolean
     */
    public boolean isPalindrome(ListNode head) {
        // Write your code here
        ArrayList<Integer> list = new ArrayList<Integer>();
        if(head == null || head.next == null)
            return true;
        ListNode p = head;
        ListNode prev = new ListNode(head.val);
        while(p.next != null){
            ListNode tmp = new ListNode(p.next.val);
            tmp.next = prev;
            prev = tmp;
            p = p.next;
        }
        ListNode p1 = head;
        ListNode p2 = prev;
        while(p1!=null){
            if(p1.val != p2.val)
                return false;
            p1 = p1.next;
            p2 = p2.next;
        }
        return true;
     
    }
}
Java Code

总耗时: 2219 ms

Python下面程序出现内存溢出

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

class Solution:
    # @param head, a ListNode
    # @return a boolean
    def isPalindrome(self, head):
        # Write your code here
        if head == None or head.next == None:
            return True
        p = head
        prev = ListNode(head.val)
        while p.next!=None:
            tmp = ListNode(p.next.val)
            tmp.next = prev
            prev = tmp
            p = p.next
        p1 = head
        p2 = prev
        del head
        del prev
        while p1!=None:
            if p1.val != p2.val:
                return False
            p1 = p1.next
            p2 = p2.next
        return True 
Python Code

法二:

先找到链表的中间节点,根据中间节点划分成两个链表,对第二个链表反转后在和第一个链表元素以此比较,但是下面的程序,在旋转的过程中空间复杂度好像是O(N/2) = O(N)

在找中间节点时候需要说明下

        ListNode slow = head;
        ListNode fast = head;
        // 找到两个链表的中间节点
        while( fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }

开始时候两个节点都指向第一个节点,以后两个异步的向前走

最后结束的时候

当长度是奇数的时候:slow恰好在中间节点,fast恰好在最后一个节点。slow.next就是下一个链表的头节点。你会发现这两个链表是不一样的长的,但是在比较的时候,只要有一个链表是null的时候就结束比较的,也就是说只与第二个链表有关系的。

当长度是偶数的时候:slow在N/2的下取整处的节点,也就是中间两个节点的前一个,二fast在倒数第二个节点,下面就一样了

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param head a ListNode
     * @return a boolean
     */
    public boolean isPalindrome(ListNode head) {
        // Write your code here
        if(head == null || head.next == null)
            return true;
        ListNode slow = head;
        ListNode fast = head;
        // 找到两个链表的中间节点
        while( fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode secondHead = slow.next;
        slow.next = null;
        // 后半部分的节点反转
        ListNode p1 = secondHead;
        ListNode revsecondList = new ListNode(p1.val);
        revsecondList.next = null;
        while(p1.next != null){
            ListNode tmp = new ListNode(p1.next.val);
            tmp.next = revsecondList;
            revsecondList = tmp;
            p1 = p1.next;
        }
        
        // 比较两个链表
        while(head!=null && revsecondList!=null){
            if(head.val != revsecondList.val)
                return false;
            head = head.next;
            revsecondList = revsecondList.next;
        }
        return true;
    }
}
Java Code

总耗时: 2229 ms

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

class Solution:
    # @param head, a ListNode
    # @return a boolean
    def isPalindrome(self, head):
        # Write your code here
        if head == None or head.next == None:
            return True
        slow = head
        fast = head
        while fast.next != None and fast.next.next != None:
            fast = fast.next.next
            slow = slow.next
        secondHead = slow.next
        slow.next = None
        p = secondHead
        rev = ListNode(p.val) 
        
        while p.next!=None:
            tmp = ListNode(p.next.val)
            tmp.next = rev
            rev = tmp
            p = p.next

        while rev!=None and head!=None:
            if rev.val != head.val:
                return False
            rev = rev.next
            head = head.next
        return True 
Python Code

总耗时: 528 ms

在旋转链表的时候有重新定义了节点,如何只是修改节点而实现翻转,下面利用递归的思想翻转链表,但是在测试到97%的数据的时候运行时间超时。

    public ListNode reverse(ListNode head){
        if(head == null || head.next == null)
            return head;
        ListNode second = head.next;
        head.next = null;
        ListNode res = reverse(second);
        second.next = head;
        return res;
    }
Java Code

下面是定义两个指针,第一个指向头节点,第二个指向头节点后一个节点

p1 = head
p2 = p1.next
while(p1!= null && p2!= null){ ListNode tmp = p2.next; p2.next = p1; p1 = p2; p2 = tmp; }

操作如下图所示

这里可以最后A还指向B的,可以在初始定义中增加

p1 .next = null

这样每次都是在p1节点之前增加一个节点的

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    /**
     * @param head a ListNode
     * @return a boolean
     */
    public boolean isPalindrome(ListNode head) {
        // Write your code here
        if(head == null || head.next == null)
            return true;
        ListNode slow = head;
        ListNode fast = head;
        // 找到两个链表的中间节点
        while( fast.next!=null && fast.next.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        ListNode secondHead = slow.next;
        slow.next = null;
        // 后半部分的节点反转
        ListNode p1 = secondHead;
        ListNode p2 = p1.next;
        p1.next = null;

        while(p1!= null && p2!= null){
            ListNode tmp = p2.next;
            p2.next = p1;
            p1 = p2;
            p2 = tmp;
        }
        secondHead.next = null;
        revsecondList = p1;
        // 比较两个链表
        while(head!=null && revsecondList!=null){
            if(head.val != revsecondList.val)
                return false;
            head = head.next;
            revsecondList = revsecondList.next;
        }
        return true;
    }
}
Java Code

总耗时: 2192 ms

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

class Solution:
    # @param head, a ListNode
    # @return a boolean
    def isPalindrome(self, head):
        # Write your code here
        if head == None or head.next == None:
            return True
        fast = head
        slow = head
        while fast.next!= None and fast.next.next!=None:
            fast =fast.next.next
            slow = slow.next
        secondhead = slow.next
        slow.next = None
        
        p1 = secondhead
        p2 = p1.next
        p1.next = None
        while p1!=None and p2!=None:
            tmp = p2.next
            p2.next = p1
            p1 = p2
            p2 = tmp
        rev = p1
        while rev!=None and head!=None:
            if rev.val!=head.val:
                return False
            rev = rev.next
            head = head.next
        return True 
Python Code

总耗时: 516 ms