判断链表是否为回文链表的几种实现方式学习总结

示例:如果一个链表为 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;
    }
}

测试结果(可能包含没有考虑到的其他情况,望指正):

  • 14
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值