PalindromeLinkedList [source code]
public class PalindromeLinkedList {
static
/******************************************************************************/
public class Solution {
public boolean isPalindrome(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
if (fast != null) {
slow = slow.next;
}
slow = reverse(slow);
while (head != null && slow != null) {
if (head.val != slow.val) return false;
head = head.next;
slow = slow.next;
}
return true;
}
public ListNode reverse(ListNode head) {
ListNode prev = null;
while (head != null) {
ListNode next = head.next;
head.next = prev;
prev = head;
head = next;
}
return prev;
}
}
/******************************************************************************/
public static void main(String[] args) {
PalindromeLinkedList.Solution tester = new PalindromeLinkedList.Solution();
int N = 11;
int half = N % 2 == 0 ? N / 2 - 1 : N / 2;
ListNode[] nodes = new ListNode[N];
for (int i = 0; i <= half; i++) {
nodes[i] = new ListNode(i);
}
for (int i = N - 1; i >= 0 && nodes[i] == null; i--) {
nodes[i] = new ListNode(N - 1 - i);
}
for (int i = 0; i < N - 1; i++) nodes[i].next = nodes[i + 1];
ListNode head = nodes[0];
System.out.println(tester.isPalindrome(head));
}
}
不要急着立刻就想 Follow-Up, 先想笨办法;
这题的笨办法比较简单, 直接走一遍, 全部放到一个 array 里面, 然后array 里面就好解决了;
一个比较 naive 的想法是把 ListNode 给 wrap 到一个DoublyLinkedList的 node 里面, 不过这样好像应该还是算有额外空间的;
总结一下寻找O(1) space 的一般思路:
- recursion: 因为一般recursion stack不算是extra space;
- pattern 题, 这个不用说的;
- bit manipulation;
- InPlace 操作: 这一题就是这样;
- historical stream: 而且并不是所有的历史流都可以做到O(1)空间, 只有一些特殊的, 比如某些特殊的 DP, 可以做到; 或者类似moore voting这样的;
这题最起码你要学完的一个地方就是 reverse 的 iterative 写法要写的非常熟练了;
另外我目前有一个隐约的感觉, 好像涉及到 LinkedList 的题目, 就那么几个常规操作, 包括 reverse. 感觉把相关的题目多做一点之后应该会熟悉一些;
另外这里一个快慢指针找终点的方法也可以稍微学习一下; 这个做法的好处就是不用专门跑一遍来找 size: how to find the median in O(N) time without knowing the size;
这题的大部分思路都是依靠 reverse, 但是 discussion 里面有一个我个人认为非常聪明的解:
public class Solution {
ListNode h;
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
if (h == null) h = head;
boolean tmp = true;
if (head.next != null) tmp &= isPalindrome(head.next);
tmp &= (head.val == h.val);
h = h.next;
return tmp;
}
}
这个解刚开始我用 recursion 的思路来看它, 其实不是很好理解; 但是这个解如果你用 DFS 的思路来理解, 就好理解的多; 这个问题难写的一个原因就是因为没有办法获得尾巴的信息; 或者general 的说, 没有办法完成一个从尾巴向上回头的问题, 普通的指针 traversal 做不到这一点; 这个人这里用 recursion 的方法就是为了达到一个上行的作用, 可以说这个跟你单独用一个 Stack 来做是差不多的原理(所有路过的全都 push 进去), 不过如果是面试, 这个答案是可以过no extra space的要求的;
这个算法可以提炼出来的一个中心思想就是: 可以用 recursion 来做singly linked list的reversed traversal. 当然你也可以说用 recursion 来做对称分析, 不过不如reversed traversal来的 general;
我个人认为这个算法比直白的reverse list更加的 elegant;
当然他具体的写法上还是有一定的技巧的, 他这里的技巧就是每次退出一个 node 的时候, 这个 global 的 h 都要向下移动一格, 保持对称位置;
这个算法刚开始看到的时候我尝试直接用 recursion 来理解, 就是考虑当前level 的 node 跟自己的两个 child 之间的关系(DP Property), 但是这样考虑了半天好像还是没有用; 最后就只能画 trace, 画 trace 的时候从一个简单的例子开始, 不要想的太复杂1 -> 2 -> 1就可以了, 这个 trace 跑一遍就知道这个算法的核心更多的是接近 DFS 而不是 recursion;
如果非要用recursion来解释, 这里的 DP value 好像可以说是: whether head equals the node in the mirror position; 不过这个只能说有点牵强了, 这个算法还是从imperative 的角度更好理解;
Problem 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?
Difficulty:Easy
Total Accepted:107.1K
Total Submissions:329.5K
Contributor: LeetCode
Companies
amazon facebook
Related Topics
linked list two pointers
Similar Questions
Palindrome Number Valid Palindrome Reverse Linked List