题目描述:
Given a singly linked list, determine if it is a palindrome.
Example 1:
Input: 1->2
Output: false
Example 2:
Input: 1->2->2->1
Output: true
Follow up:
Could you do it in O(n) time and O(1) space?
样例考虑:
[] ture
[1] ture
[1,2,1] true
[1,2,2,1] true
思路:双指针+栈
首先要考虑边界问题,还要考虑链表的总长度是奇数个还是偶数个。
用两个指针,一个快指针、一个慢指针,找到链表的中间位置(偶数的话,慢指针就是找到的[1,2,2,1],奇数的话,慢指针就是找到的[1,2,1],这样的情况,就让慢指针往后移动一位,即:[1,2,1])
在寻找链表中间位置的过程中,将慢指针遍历到的元素入栈,找到中间元素后,栈顶出栈,并与慢指针比较
代码:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
if(head == null || head.next == null) return true;
ListNode kuai = head ;
ListNode man = head ;
Stack<Integer> st =new Stack<Integer>();
//入栈
while(kuai !=null && kuai.next != null){
st.push(man.val);
kuai = kuai.next.next;
man = man.next;
}
if(kuai != null){
//奇数个
man = man.next;
}
//偶数个 不需要处理
while (man != null){
if(man.val != st.pop()) return false;
man = man.next;
}
if(st.isEmpty()) return true;
return false;
}
}
应该还有可以改进的地方:
用反转链表的方法
还是要用双指针找到中间的位置,在找的过程中,(上面是入栈)反转链表
下面参考:https://blog.csdn.net/sunao2002002/article/details/46918645
算法有以下几种:
1、遍历整个链表,将链表每个节点的值记录在数组中,再判断数组是不是一个回文数组,时间复杂度为O(n),但空间复杂度也为O(n),不满足空间复杂度要求。
2、利用栈先进后出的性质,将链表前半段压入栈中,再逐个弹出与链表后半段比较。时间复杂度O(n),但仍然需要n/2的栈空间,空间复杂度为O(n)。
3、反转链表法,将链表后半段原地翻转,再将前半段、后半段依次比较,判断是否相等,时间复杂度O(n),空间复杂度为O(1)满足题目要求。
链表翻转可以参考LeetCode 206 Reverse Linked List的代码。
代码如下:
bool isParadom(ListNode * head)
{
//如果链表为空或者仅有一个元素那么肯定是回文链表
if (!head || !head->next) {
return true;
}
//快慢指针法,寻找链表中心
ListNode * slow, *fast;
slow = fast = head;
while (fast && fast->next) {
slow = slow->next;
fast = fast->next->next;
}
if (fast) {
//链表元素奇数个
slow->next = reverseList(slow->next);
slow = slow->next;
}else{
//链表元素偶数个
slow = reverseList(slow);
}
while (slow) {
if (head->val != slow->val) {
return false;
}
slow = slow->next;
head = head->next;
}
return true;
}