Idiot-maker

  :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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

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?

解题思路:

CC150中的原题2.7。

有好几种解法。首先,如果题目不要求O(1)的空间的话。使用快慢指针,找到list的中点的同时,将前半段的每个结点的值加入到一个stack中。后面从中点向后遍历的同时,逐个弹出栈顶元素。用这种方式完成前半段的倒置。

需要注意的是,如何判断list的结点数量是奇数个的方法。如果最后fast!=null的话,说明是奇数个。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isPalindrome(ListNode head) {
        Stack<Integer> stack = new Stack<Integer>();
        ListNode fast = head, slow = head;
        while(fast != null && fast.next != null) {
            stack.push(slow.val);
            fast = fast.next.next;
            slow = slow.next;
        }
        // 奇数个结点
        if(fast != null) {
            slow = slow.next;
        }
        while(slow != null) {
            if(slow.val != stack.pop()) {
                return false;
            }
            slow = slow.next;
        }
        return true;
    }
}

注意点,先push再next,否则[1,2]的case1不会被push进去,就是tru了。第二,判断条件不是while (fast.next =! null && fast.next.next != null) 。

但是,本题要求是O(1)的空间。其实也很简单,但是代码复杂了一些。获得list的中点后,将右半段转置。然后两个指针,分别指向左半段的head和右半段转置后的head,往后逐个遍历对比。

最后再将右半段转置回去。因为不能破坏原list的结构。事实上,如果不转置也能AC。

需要注意的是,reverse(ListNode head)的方法,是转置以head开头的链表,但是并不改变head的前一个结点的next一直指向head。所以,无论右半段如何转置,前一个结点都不会变,也不会引起死循环。这是写给自己看的话。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
public class Solution {
    public boolean isPalindrome(ListNode head) {
        ListNode fast = head, slow = head;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        // 奇数个结点
        if(fast != null) {
            slow = slow.next;
        }
        // 右半侧反向
        ListNode right = reverse(slow);
        ListNode left = head;
        boolean res = true;
        while(right != null) {
            if(left.val != right.val) {
                res = false;
                break;
            }
            left = left.next;
            right = right.next;
        }
        // 恢复右半侧
        reverse(right);
        return res;
    }
    
    public ListNode reverse(ListNode head) {
        ListNode pre = null;
        while(head != null) {
            ListNode next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }
}

 

posted on 2015-07-10 10:38  NickyYe  阅读(335)  评论(0编辑  收藏  举报