前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >单链表回文判断

单链表回文判断

作者头像
WindCoder
发布2020-01-23 20:56:28
4840
发布2020-01-23 20:56:28
举报
文章被收录于专栏:WindCoderWindCoder

判断一个单链表是否为回文链表目前有两种实现思路。一种是通过数组记录前半部分与后半部分依次比较,一种是找到链表中间结点,将左半部分反转与右半部分依次比较,下面详细介绍。

基于数组

用数组存储链表前半段的值,使用快慢指针法来进行截取。

代码语言:javascript
复制
public boolean isPalindromeByArray(Node node){
        if (node == null) return false;
        Node fast = node;
        Node slow = node;
        if (node.next == null) return true;

        /**
         * 找到中间结点,同时用数组逆插左侧元素并保存。
         *  nodeList.add(0, slow.data); 在指定位置插入元素,原位置及之后的依次向右移动一位。
         */
        List<Integer> nodeList = new ArrayList<Integer>();
        nodeList.add(0, slow.data);
        while (fast.next != null && fast.next.next != null ) {

            fast = fast.next.next;
            slow = slow.next;
            nodeList.add(0, slow.data);
        }


        if (fast.next != null){
            // fast.next不为空,数据为偶数。
            slow = slow.next;
        }
        Node curr = slow;
        int i = 0;
        while (null != curr){
            if (curr.data != nodeList.get(i)){
                return false;
            }
            curr = curr.next;
            i++;
        }
        return true;
    }

nodeList.add(0, slow.data);插入是比较耗时的,毕竟每次插入都需要将之前的依次向右移动一位。所以可以考虑用栈实现。

基于栈的回文判断

思路同基于数组的,但因为免去了保存新结点的右移操作,所以比使用数组保存左侧数据的方式高效一些。

代码语言:javascript
复制
/**
     * 基于栈比较是否为回文--半栈
     * @param node
     * @return
     */
    public boolean isPalindromeByStack(Node node){
        if (node == null) return false;
        Node fast = node;
        Node slow = node;
        if (node.next == null) return true;

        /**
         * 找到中间结点,同时用栈保存左侧数据。
         *  
         */
        Stack<Integer> nodeList = new Stack<Integer>();
        nodeList.push(slow.data); // 1 2 3
        while (fast.next != null && fast.next.next != null ) {

            fast = fast.next.next;
            slow = slow.next;
            nodeList.push(slow.data); // 1 2 3
        }


        if (fast.next != null){
            // fast.next不为空,数据为偶数。
            slow = slow.next;
        }
        Node curr = slow;
        int i = 0;
        while (null != curr){
            if (curr.data != nodeList.pop()){
                return false;
            }
            curr = curr.next;
            i++;
        }
        return true;
    }

基于链表反转的回文判断

该方案的思路是:通过快慢指针获取中间结点,反转中间结点左侧部分,遍历并对比反转后左右两侧结点的数据判是否为回文。

只需要固定的若干个临时变量,不需要额外开辟空间

时间复杂度为O(n),空间复杂度为O(1)

该方式可以略作简化将反转左侧部分在查中间结点时同时完成。这里为了方便阅读,分开了查找中间结点和反转左侧结点的步骤,不再实现该优化。

代码语言:javascript
复制
    /**
     * 不含逻辑头节点的回文链表判断
     * 思路:
     * 遍历一遍链表,得到链表长度n,根据长度的奇偶,找到中间节点,将左半边的链表反转,然后从中间节点分两个方向向左右两边遍历,是否是回文;
     * 
     * 对左半部分链表进行反转,还原为最初的链表(目前函数未实现左半部分链表还原)
     * 
     * 
     * 1 2 3 4 5 8 9 slow 4 fast 9
     * 1 2 3 4 5 8  slow  3 fast 5
     * @return
     */
    public  boolean isPalindrome(Node head){
        if (head == null) return false;
        PrintUtill.println("开始执行找到中间节点");
        Node fast = head;
        Node slow = head;
        if (fast.next == null){
            System.out.println("只有一个元素");
            return true;
        }
        /**
         * 快的一次走两步,慢的一次走一步那么最后快的结束了慢的走了一半
         */
        while (fast.next !=null && fast.next.next != null){
            fast = fast.next.next;
            slow = slow.next;
        }
        Node leftLink = null;
        Node rightLink = null;
        /**
         * 获取中间结点左右两部分,反转左侧部分。
         * fast.next == null :节点数目为奇数,且slow一定为为中间节点
         * fast.next.next  == null :节点数目为偶数,slow、slow.next 均为中心结点
         */
        rightLink = slow.next;
        if (fast.next  == null){
            leftLink = inverseLinkListToEnd(slow).next;
        }else {
            leftLink = inverseLinkListToEnd(slow);
        }
        /**
         * 从此处开始同步向两边比较
         */
        return TFResult(leftLink, rightLink);
    }
    /**
     * 比较是否为回文
     * @param left
     * @param right
     * @return
     */
    public boolean TFResult(Node left, Node right){

        while (left != null && right != null){
            if (left.data != right.data){
                return false;
            }
            left = left.next;
            right = right.next;
        }

        return true;
    }


    /**
     * 反转中间结点的左半部分,返回以end结点为头节点的链表。
     * @param end
     * @return
     */
    public Node inverseLinkListToEnd(Node end) {
        Node pre = null;
        Node cur = head;
        Node next = null;

        /**
         * 反转中间结点之前的结点
         */
        while (cur!=end){
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }
        cur.next = pre;
        return cur;
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 基于数组
  • 基于栈的回文判断
  • 基于链表反转的回文判断
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档