java算法系列,第十二篇,判断回文链表

什么是回文链表?

就是下面这种:

[1,2,2,1] 倒过来仍然是[1,2,2,1],啊,“上山西去运煤,煤运去西山上”  就是这个感觉。

第一种方法:

/*
* 步骤1:找中间节点
* 步骤2:将中间节点后半段反转
* 步骤3:比较两段
* */

步骤1:找中间节点

使用快慢指针法找中间节点,让p1一次走一步,p2一次走两步,等p2走完了,p1刚好走了一半,这样就找到中间节点了。

 /**
     * 找中间节点
     * @param head 原链表的头结点
     * @return     中间节点
     */
    private ListNode mid(final ListNode head)
    {
        ListNode p1 = head;
        ListNode p2 = head;
        while (p2 != null && p2.getNext() != null)
        {
            p1 = p1.getNext();
            p2 = p2.getNext().getNext();
        }
        return p1;
    }

步骤2:将中间节点后半段反转

反转链表我前面有几篇博客已经专门介绍了,这里就不过多解释了。

 /**
     * 反转链表
     * @param oldHead 原链表的头结点
     * @return        反转后的链表的头结点
     */
    private ListNode reverse(ListNode oldHead)
    {
        ListNode newNode = null;
        while (oldHead != null)
        {
            ListNode oldNode = oldHead.getNext();
            oldHead.setNext(newNode);
            newNode = oldHead;
            oldHead = oldNode;
        }
        return newNode;
    }

步骤3:比较两段

 /**
     * 判断回文链表
     * @param oldHead 原链表的头结点
     * @return        是否是回文链表
     */
    public boolean isPalindrome(ListNode oldHead)
    {
        ListNode newHead = reverse(mid(oldHead));//通过前两步得到一个反转了的后半段链表
        while (newHead != null)//只要得到的新链表不为空就一直比较下去
        {
            if (newHead.getVal() == oldHead.getVal())//两个链表的值相等,继续往后面比较
            {
                newHead = newHead.getNext();
                oldHead = oldHead.getNext();
            }
            else//一旦有不相等,直接返回false
            {
                return false;
            }
        }
        return true;
    }

第二种方式:

第二种是对第一种的优化:

/* 优化
* 步骤1:找中间节点的同时将前半段反转
* 步骤2:比较前半段的反转与后半段
* */

由于第一种方式走了三次循环,所以它的时间复杂度不理想,现在采用 ’找中间节点的同时将前半段反转‘  的方式来减少一个循环
 

 /**
     * 判断回文链表
     * @param oldHead 原链表的头结点
     * @return        是否是回文链表
     */
    public boolean isPalindrome2(ListNode oldHead)
    {
        ListNode[] listNodes = mid2(oldHead);
        ListNode reverseList = listNodes[1];
        ListNode mid = listNodes[0];
        
        while (mid != null)
        {
            if (mid.getVal() == reverseList.getVal())
            {
                mid = mid.getNext();
                reverseList = reverseList.getNext();
            }
            else
            {
                return false;
            }
        }
        return true;
    }
    /**
     * 找中间节点
     * @param head 原链表的头结点
     * @return     中间节点和前半段反转后的链表的头结点
     */
    private ListNode[] mid2(ListNode head)
    {
        ListNode p1 = head;
        ListNode p2 = head;
        ListNode oldHead = head;
        ListNode newHead = null;
        while (p2 != null && p2.getNext() != null)
        {
            //找中间节点
            p1 = p1.getNext();
            p2 = p2.getNext().getNext();
            
            //反转前半段
            oldHead.setNext(newHead);
            newHead = oldHead;
            oldHead = p1;
        }
        if (p2 != null)//如果链表长度为奇数,就把中间节点后移
        {
            p1 = p1.getNext();
        }
        return new ListNode[]{p1, newHead};
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值