场景描述
请判断一个链表是否为回文链表。
示例 1:
输入: 1->2
输出: false
示例 2:
输入: 1->2->2->1
输出: true
进阶:
你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
C语言实现
初步思路
按照描述,一个链表是回文链表,那么它的前半部分和它的后半部分的逆序应该是一模一样的。因此我们应找到它中间的结点,以此为分割点将链表分为两部分。而可以通过双指针的技巧使得只遍历一边链表就找到中间结点。接下将后半部分的链表反转后和前半部分链表进行比较即可。
具体过程
寻找中间结点:设立快慢指针,快指针速度是慢指针速度的两倍,同时从链表首出发,当快指针到达链表尾时,慢指针到达链表中间。关于双指针的一些应用还可见:删除链表倒数第n个结点 找出环链表的入口结点 判断链表是否相交
反转链表:详见:反转链表
代码实现
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool isPalindrome(struct ListNode* head){
struct ListNode* dummyNode = (struct ListNode*) malloc(sizeof(struct ListNode));
struct ListNode* slow = dummyNode;
struct ListNode* fast = dummyNode;
dummyNode->next = head;
while(fast&&fast->next){
slow = slow->next;
fast = fast->next->next;
}//最后退出循环时,slow指向链表中间的结点
//接下来反转后半部分链表
struct ListNode* tmp = NULL;
struct ListNode* prev = NULL;
struct ListNode* current = slow->next;
while(current) {
tmp = current->next;
current->next = prev;
prev = current;
current = tmp;
}//最后退出循环时,prev指向了原链表最后一个结点,
//即反转部分的链表第一个结点
//下面开始比较前半部分和后半部分链表
current = dummyNode->next;
while(prev){
if(prev->val == current->val) {
prev = prev->next;
current = current->next;
}
else
return false;
}
return true;
}
Java语言实现
代码实现
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isPalindrome(ListNode head) {
ListNode dummyNode = new ListNode(0);
ListNode fast = dummyNode;
ListNode slow = dummyNode;
dummyNode.next = head;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
ListNode current = slow.next;
ListNode previous = null;
ListNode tmp = null;
while(current != null){
tmp = current.next;
current.next = previous;
previous = current;
current = tmp;
}
current = head;
while(previous != null){
if(previous.val==current.val){
previous = previous.next;
current = current.next;
}
else
return false;
}
return true;
}
}