赞
踩
示例:如果一个链表为 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;
- }
- }
测试结果(可能包含没有考虑到的其他情况,望指正):
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。