题目: 编写一个函数,检查输入的链表是否是回文的。
示例:
进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?
方法一:反转链表比较值
思路:
1.计算链表长度
2.翻转前半部分链表。
比如 1->2->3->3->2->1,将其翻转为1<-2<-3 3->2->1。链表长度为奇数时不用管最中间的那个节点。
3.从两个子链表的head开始,一一比较节点值,如果有不一样,就返回false,全部一样返回true
时间复杂度O(n),空间复杂度O(1)
public boolean isPalindrome(ListNode head) {
if (head == null) return true;
//1.计算链表长度
int length = 0;
ListNode tmp = head;
while (tmp != null) {
length++;
tmp = tmp.next;
}
//因为翻转链表时需要3个引用,所以对长度小于3的做特殊化处理。
if (length == 1) return true;
if (length == 2) return head.val == head.next.val;
//2.翻转前半部分链表。
ListNode pre = head;
ListNode cur = head.next;
ListNode next = head.next.next;
pre.next = null;
//翻转链表实际上就是把currrent节点里的next引用指向pre指向的那个节点。。
//翻转当前节点完毕后,把pre引用指向current,把current引用指向next,把next引用指向next.next,这样就可以继续翻转下一个节点了。
for (int i = 1; i < length / 2; i++) {
cur.next = pre;
pre = cur;
cur = next;
next = next.next;
}
//翻转完毕后,如果链表长度为偶数,pre正好指向前半个链表的表头,cur正好指向后半个链表的表头
//如果链表长度为奇数,pre指向前半个链表的表头,next指向后半个链表的表头,cur指向最中间的节点。
//所以把cur指向next的那个节点,奇偶两种情况就可以共用下面的while循环了。
if (length % 2 != 0) cur = next;
while (pre != null && cur != null) {
if (pre.val != cur.val) return false;
pre = pre.next;
cur = cur.next;
}
return true;
}