示例:如果一个链表为 1 -> 2 -> 3 -> 2 -> 1;
它的正序遍历结果等于它的倒序遍历结果,那么它就是回文链表;
第一种实现: 判断一个链表是不是回文链表的第一种实现,使用一个栈、并遍历两次链表 第一遍遍历将链表的元素添加至栈中,第二遍遍历的过程中依次弹出栈中的元素进行比较。时间复杂度:O(N);空间复杂度:O(N);
代码实现:
public class isHuiWenListNodeFirst {
public static void main(String[] args) {
Scanner sc= new Scanner(System.in);
int n = sc.nextInt(); //链表的节点的个数
ListNode head = new ListNode(sc.nextInt());
ListNode pre = head;
while (n>1){
n--;
pre.next = new ListNode(sc.nextInt());
pre = pre.next;
}
System.out.println(isOrNot(head));
}
public static boolean isOrNot(ListNode head){
ListNode pre = head;
LinkedList<Integer> stack = new LinkedList<>();
while(pre!=null){
stack.push(pre.val);
pre = pre.next;
}
while(!stack.isEmpty()){
if(head.val != stack.poll()) return false;
head = head.next;
}
return true;
}
}
测试结果正确;(未作head是否为空的判断处理)
方法二:在方法一的基础上进行剪枝操作。双指针,慢指针每次移动一个位置,快指针每次移动两个位置。当快指针走到链表的中点时,慢指针指向的位置就是中间的位置;时间复杂度:O(N);空间复杂度:O(N);
代码实现:
public class isHuiWenListNodeFirst {
public static void main(String[] args) {
Scanner sc= new Scanner(System.in);
int n = sc.nextInt(); //链表的节点的个数
ListNode head = new ListNode(sc.nextInt());
ListNode pre = head;
while (n>1){
n--;
pre.next = new ListNode(sc.nextInt());
pre = pre.next;
}
System.out.println(isOrNot(head));
}
public static boolean isOrNot(ListNode head){
if (head == null || head.next == null) return true;
ListNode pre = head;
LinkedList<Integer> stack = new LinkedList<>();
ListNode slow = head; //慢指针
ListNode fast = head; //快指针
while(fast.next!=null && fast.next.next!=null){
slow = slow.next;
fast = fast.next.next;
}
//此时开始遍历 slow 指针,依次将其遍历到的元素添加至栈中
while(slow!=null){
stack.push(slow.val);
slow = slow.next;
}
//开始遍历链表的前一半,并弹出栈中的元素做比较
while(!stack.isEmpty()){
Integer poll = stack.poll();
if(pre.val!=poll){
return false;
}
pre = pre.next;
}
return true;
}
}
分别测试链表节点个数为奇数和偶数的情况:
测试结果正确(可能包含没有考虑到的其他情况,望指正)
方法三:仍然使用快慢指针,与方法二不同的地方:当慢指针走到中点时,快指针走到末尾。此时记录下来快指针的位置的节点。快指针开始向后遍历反转后半部分的链表,反转结束之后,使用双指针,left 指针指向链表的第一个节点。right 指针指向链表最右侧的节点,left 指针从前往后遍历,right 指针从后向前遍历,依次比较两个指针指向的元素,如果不相等返回 false 。时间复杂度:O(N);空间复杂度:O(1);没有使用额外的空间。
代码实现:
public class isHuiWenListNodeFirst {
public static void main(String[] args) {
Scanner sc= new Scanner(System.in);
int n = sc.nextInt(); //链表的节点的个数
ListNode head = new ListNode(sc.nextInt());
ListNode pre = head;
while (n>1){
n--;
pre.next = new ListNode(sc.nextInt());
pre = pre.next;
}
System.out.println(isOrNot(head));
}
public static boolean isOrNot(ListNode head){
//先将特殊情况做处理;
if (head == null || head.next == null) return true;
if (head.next!=null&&head.next.next==null&&head.val==head.next.val) return true;
ListNode left = head;
ListNode right;
ListNode slow = head;
ListNode fast = head;
//如果节点个数是奇数,那么fast最终指向的位置是最后一个节点
//如果节点个数是偶数,那么fast指向的位置是最后一个节点的前一个元素,此时还需要让fast后移一位
while(fast.next!=null && fast.next.next!=null){
slow = slow.next;
fast = fast.next.next;
if(fast.next!=null && fast.next.next==null) fast = fast.next;
}
//记录下来末尾节点
//开始反转链表,反转 slow 之后的节点
right = slow.next;
ListNode tmp = right.next;
slow.next = null;
right.next = slow;
slow = right;
right = tmp;
//循环结束之后,right为null,slow指向最后一个节点,至此后半部分的链表反转完成
while(right!=null){
tmp = right.next;
right.next = slow;
slow = right;
right = tmp;
}
right = slow;
//开始比较元素的值
while(left!=null){
if(left.val!= right.val) return false;
left = left.next;
right = right.next;
}
return true;
}
}
测试结果(可能包含没有考虑到的其他情况,望指正):