题目:请判断一个链表是否为回文链表。
解析:
1.利用栈求解
①首先遍历链表获取链表的长度len;
②根据链表的长度,将链表的前半部分压入栈,将后半部分依次与弹栈的元素比较看是否一致,一致则为回文链表;
③这里注意的是链表的后半部分的开始位置(链表长度的奇偶)。
public boolean isPalindrome1(ListNode head) {
if (head == null) return true;
if (head.next == null) return true;//链表只有一个的时候
int len = 0;
ListNode first = head;
//链表的长度
while (head != null){
head = head.next;
len++;
}
//前半部分压入栈
Stack<Integer> stack = new Stack<Integer>();
int mid = len/2;
if (len%2 == 0){
while ((mid--)!=0){
stack.push(first.val);
first = first.next;
}
//注意区分mid--和--mid时遍历停止时的first指向的结点
//链表长度是偶数,此时first表示链表后半部分的开始
}else{
while ((mid--)!=0){
stack.push(first.val);
first = first.next;
}
first = first.next;
//链表长度是奇数,此时first表示链表后半部分的开始
}
//后半部分与栈中元素比较
while (first!=null){
if (first.val != stack.pop())
return false;
first = first.next;
}
return true;
}
2.双指针—链表反转
①定义两个指针p1和p2,开始同时指向头结点;
②指针p1和p2同时移动,p1移动一个节点,p2移动两个结点,当p2移动到链表的末尾无法在移动时,此时p1刚好指向链表的中间结点;
例:
1->2->2->1 p1停留在第一个结点2上
1->2->3->2->1 p1停留在结点3上
③进行反转p1后面的部分链表操作;
④比较前半部分的链表和反转的后半部分链表。(从上述例中明显可以看出,不区分链表的奇偶)
public boolean isPalindrome2(ListNode head) {
if (head == null) return true;
if (head.next == null) return true;
ListNode p1 = head, p2 = head;
//利用快慢指针,将p1移动到链表的中间部分
while (p2.next != null && p2.next.next != null){
p1 = p1.next;
p2 = p2.next.next;
}
//反转此时p1之后的链表
//不用考虑链表的奇偶
ListNode pre = null, curnode = null, tmpnode = p1.next;
while (tmpnode != null){
curnode = tmpnode.next;
tmpnode.next = pre;
pre = tmpnode;
tmpnode = curnode;
}
p1.next = pre;//接上反转后的链表
//比较前半部分和反转后的部分是否一致
while(pre != null){
if (head.val != pre.val)
return false;
head = head.next;
pre = pre.next;
}
return true;
}