题目:对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
示例:1->2->2->1
返回:true
思路:
1.大体思路:找到链表的中间结点( mid ),再反转任意一半链表,变成两条链表。再依次比较两个链表中的每个结点,如果全部相等则返回 true ,如果有一个不相等,则返回 false。
2.找链表中间结点:有两种方法:找规律法和双指针法( 快慢引用 )。两种方法选一种即可。我们这里使用找规律法:4 个元素的链表中间结点为第 3 个元素,需要从头结点开始跳 2 次;5 个元素的链表中间结点为第 3 个元素,需要从头结点开始向后跳 2 次;所以要想找到中间结点,需要跳x = size / 2 下 。 找链表中间结点的详细思路与步骤(带图)
3.反转其中任意一半链表:反转后一半链表,传入中间结点。要想反转链表,需要三个引用,分别为 prev ( 记录前一个结点 )、cur ( 记录当前需要操作的结点 )、next ( 记录操作结点的后一个结点,因为改变 cur 指向的对象后,无法直接根据 cur 访问原来链表的下一个结点了)。主要操作步骤:①让 next 指向 cur.next 提前记录cur 的下一个元素;②将 cur.next 指向 prev 对象;③ 更新 prev 和 cur ;反转链表的详细思路与步骤(带图)
4.比较问题:考虑奇数个链表元素和偶数个链表元素的情况。
代码:
public class Solution {
//找中间结点:找规律法
public static int size(ListNode A){
int size = 0;
ListNode cur = A;
while (cur != null){
size++;
cur = cur.next;
}
return size;
}
public static ListNode mid(ListNode A){
ListNode cur = A;
for (int i = 0; i < size(A) / 2; i++) {
cur = cur.next;
}
return cur;
}
//反转链表
public static ListNode revers(ListNode head){
ListNode cur = head;
ListNode prev = null;
while (cur != null){
ListNode next = cur.next;
cur.next = prev;
prev = cur;
cur = next;
}
return prev;
}
//判断链表是否为回文链表
public boolean chkPalindrome(ListNode A) {
ListNode mid = mid(A); //找到链表的中间结点
ListNode rHead = revers(mid); //将后半段链表进行反转
//开始进行判断
ListNode cur1 = A;
ListNode cur2 = rHead;
while (cur1 != null && cur2 != null){
if (cur1.val != cur2.val){
return false;
}
cur1 = cur1.next;
cur2 = cur2.next;
}
return true;
}
}