Leetcode - Palindrome Linked List

《Leetcode - Palindrome Linked List》 Paste_Image.png

My code:

import java.util.Stack;

/**
 * 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) {
        if (head == null || head.next == null)
            return true;
        ListNode slow = head;
        ListNode fast = head;
        Stack<Integer> s = new Stack<Integer>();
        s.push(slow.val);
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next.next;
            s.push(slow.val);
        }
        if (fast.next == null)
            s.pop();
        
        slow = slow.next;
        while (slow != null) {
            int val = slow.val;
            if (val != s.pop())
                return false;
            slow = slow.next;
        }
        return true;
    }
}

My test result:

《Leetcode - Palindrome Linked List》 Paste_Image.png

这道题目我一开始想用异或来做,后来发现错的,即使一个数字出现了偶数次,不代表他的位置是对称的,不一定是回文。
网上找了做法。
挺经典的。
先走到中间,将之前的值压在栈里面。
然后再往右走,将栈中的数据一个个弹出和之后的结点比对。

**
然后这里介绍一个技巧,是我之前完全不知道的。
用快慢指针来找一个链表的中点。
慢指针走一步,快指针走两步,同时每次循环都得判断下,
fast.next != null && fast.next.next != null
同时还有个细节。
如果是奇数个结点,则此时将中间值压入栈中了,事实上没有数字和他对应,所以需要手动弹出。

这是链表的一个小技巧。
还有个小技巧就是,设置 dummy head。 可以简单地通过许多corner case.
**

参考的博客。
http://www.cnblogs.com/grandyang/p/4635425.html

**
总结: 快慢指针找链表中点。栈
**

Anyway, Good luck, Richardo!

My code:

/**
 * 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) {
        if (head == null || head.next == null) {
            return true;
        }
        
        ArrayList<Integer> al = new ArrayList<Integer>();
        ListNode temp = head;
        while (temp != null) {
            al.add(temp.val);
            temp = temp.next;
        }
        
        int begin = 0;
        int end = al.size() - 1;
        while (begin < end) {
            if (al.get(begin).intValue() != al.get(end).intValue()) {
                return false;
            }
            begin++;
            end--;
        }
        return true;
    }
}

一开始看到回文,首先想到了string。所以想把list 转换成string。但后来发现不对,负数表示会有问题。
这里可以看出,我的思维还是不够严谨,不能提前发现问题!

然后选择使用ArrayList.同样出现了一个问题。我一直不知道哪里错了,直到用eclipse debug才发现。
我的ArrayList 里面存的是 Integer, 比较的时候不能直接 !=
应该, list.get(i).intValue ,取出 int值来进行比较。

下面重写下栈的做法。

/**
 * 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) {
        if (head == null || head.next == null) {
            return true;
        }
        
        int counter = 1;
        Stack<ListNode> s = new Stack<ListNode>();
        ListNode slow = head;
        ListNode fast = head;
        s.push(slow);
        while (fast.next != null && fast.next.next != null) {
            slow = slow.next;
            fast = fast.next;
            fast = fast.next;
            counter += 2;
            s.push(slow);
        }
        if (fast.next != null) {
            counter++;
        }
        
        if (counter % 2 == 1) {
            s.pop();
        }
        slow = slow.next;
        while (slow != null) {
            ListNode temp = s.pop();
            if (temp.val != slow.val) {
                return false;
            }
            slow = slow.next;
        }
        
        return true;
    }
}

看之前的做法,的确不用计数器。

然后得思考下,如何才能用O(1)的空间复杂度呢?

/**
 * 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) {
        if (head == null || head.next == null) {
            return true;
        }
        
        ListNode slow = head;
        ListNode fast = head;
        ListNode p = slow.next;
        // find middle, reverse
        while (fast.next != null && fast.next.next != null) {
            fast = fast.next.next;
            ListNode next = p.next;
            p.next = slow;
            slow = p;
            p = next;
        }
    
        if (fast.next == null) {
            slow = slow.next;
        }
        
        while (slow != null && p != null) {
            if (slow.val != p.val) {
                return false;
            }
            slow = slow.next;
            p = p.next;
        }
        return true;
    }
}

思路很简单,就是走到中点,将前面的链表反转,然后比较。
问题是!我改变了原链表的结构,这在实际工作中是很危险的!往往传进来的结构都应该是只读的,很容易出错,而且程序大了,根本不知道是哪个类修改了这个结构。而好处,仅仅只是,空间的确少用了很多。
但是, O(n) 空间复杂度,对于现代计算机来说,本身也是可以接受的啊!

Anyway, Good luck, Richardo! — 08/15/2016

    原文作者:Richardo92
    原文地址: https://www.jianshu.com/p/857b23f1c26f#comments
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞