leetcode连接:https://leetcode-cn.com/problems/palindrome-linked-list/
给一个简单的回文题:
有一个数组,长度为n,判断此数组是否时回文数组
如:[1,2,2,1] 长度4
这种问题比较简单,今天就不说了,回看一下上面的leetcode的问题,判断一个链表是不是回文链表,如何判断回文?肯定时拿后半部分和前半部分一一对比,如果有不一样的,则返回false,一样返回true,如果有长度,则很容易定位到一半的位置,但是链表没有长度,该如何定位到最后呢?
很简单:使用快慢指针,从头开始遍历,慢指针一步一个,快指针,一步两个往下走,当快指针的next或者快指针的next.next为空时,当前慢指针对应的节点或者下一个节点即为后半部分指针的首节点,来几张图说明一下吧
第一步:初始位置
第二步:slow往后移动一位,fast移动两位
第三步:因为fast.next和fast.next.next都不为空,则继续执行
第四步:fast.next不为空,但是fast.next.next为空,跳出循环
此时slow.next即为后半部分的头结点
以上演示的是偶数个节点,如果是奇数个节点,则fast.next为空,slow即为后半部分节点,大家可以自己画一下
我们找到了后半部分的头结点,可以遍历后半部分的节点
接下来有两种做法:第一把后半部分的节点做链表反转,如何反转可以看 链表反转, 这篇博客
然后遍历一个列表,拿另一个链表数据,一一对比判断
在这我说另一种方法,使用栈,栈的特点是先进后出,我们是不是可以在遍历链表的时候,把慢指针的节点放到栈里面?然后遍历后半部分的链表,和栈中弹出来的数据做对比,如果都一样返回true,否则返回false?
代码仅作参考:
static class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
public static boolean isPalindrome(ListNode head) {
//先使用快慢指针来获取前后各一半,当快指针的下一个指针或者下下个指针为空时, 则退出循环
//并使用栈保存前半部分的节点
ListNode slow = head;
ListNode fast = head;
Stack<ListNode> frontHalfNode = new Stack<>();
ListNode afterHalfFirstNode = null;
while (slow.next != null) {
frontHalfNode.push(slow);
if (fast.next == null) {
afterHalfFirstNode = slow;
break;
}
if (fast.next.next == null) {
afterHalfFirstNode = slow.next;
break;
}
slow = slow.next;
fast = fast.next.next;
}
while (afterHalfFirstNode != null) {
int val = afterHalfFirstNode.val;
ListNode pop = frontHalfNode.pop();
if (pop == null) {
return false;
}
if (pop.val != val) {
return false;
}
afterHalfFirstNode = afterHalfFirstNode.next;
}
return true;
}
public static void main(String[] args) {
ListNode l1 = new ListNode(1);
ListNode l2 = new ListNode(2);
ListNode l3 = new ListNode(3);
ListNode l4 = new ListNode(2);
ListNode l5 = new ListNode(1);
l1.next = l2;
l2.next = l3;
l3.next = l4;
l4.next = l5;
System.out.println(isPalindrome(l1));
}