java算法第十篇,有序链表去重

还是LeetCode上的一道题目:

现在有这么一个链表[1,1,2,3,4,5,5,5],要求你去去重,最后得到[1,2,3,4,5]

怎么来实现呢?

第一种方式:

 /**
     * 链表去重
     * @param head 头结点
     * @return     去重后的链表
     */
    public ListNode distinct(final ListNode head)
    {
        if(head == null || head.getNext() == null)//如果链表为空或者只有一个节点,就直接返回
        {
            return head;
        }
        //让p1指向头结点,p2指向头结点的下一个节点
        ListNode p1 = head;
        ListNode p2 = p1.getNext() ;
        while (p2 != null)//循环,直到p2为空
        {
            if(p1.getVal() == p2.getVal())//如果p1的值等于p2的值,就把p2移除
            {
                p1.setNext(p2.getNext());
            }
            else
            {
                p1 = p1.getNext();//如果p1的值不等于p2的值,就把p1后移
            }
            p2 = p1.getNext();//更新p2
        }
        return head;//返回去重后的链表的头结点
    }

就是让p1一开始指向头节点,p2指向它的下一个节点,然后去比较,如果p1=p2就让p1指向p2的下一个节点,然后更新一下p2,只要p2不为空,就一直往下面循环比下去。

当然为了减少耦合我们可以整理一下代码:
 

 /**
     * 链表去重
     * @param head 头结点
     * @return     去重后的链表
     */
    public ListNode distinct(final ListNode head)
    {
        if(head == null || head.getNext() == null)//如果链表为空或者只有一个节点,就直接返回
        {
            return head;
        }
        //让p1指向头结点,p2指向头结点的下一个节点
        ListNode p1 = head;
        ListNode p2 ;
        while ((p2 = p1.getNext()) != null)//循环,直到p2为空
        {
            if(p1.getVal() == p2.getVal())//如果p1的值等于p2的值,就把p2移除
            {
                p1.setNext(p2.getNext());
            }
            else
            {
                p1 = p1.getNext();//如果p1的值不等于p2的值,就把p1后移
            }
        }
        return head;//返回去重后的链表的头结点
    }

第二种方式:递归

 /**
     * 链表去重
     * @param p     起始指针
     * @return     去重后的链表
     */
    public ListNode distinct2(final ListNode p)
    {
        if(p == null || p.getNext() == null)//如果链表为空或者只有一个节点,就直接返回
        {
            return p;
        }
        if(p.getVal() == p.getNext().getVal())//如果当前节点的值等于下一个节点的值,就把下一个节点移除
        {
            return distinct2(p.getNext());//跳过当前节点继续往后比较
        }
        else//如果当前节点的值不等于下一个节点的值,就继续往后比较
        {
            p.setNext(distinct2(p.getNext()));//继续往后比较
            return p;
        }

    }

递归思路就是拿第一个节点跟后面的一个比较,如果相等,跳过第一个节点,返回从第二个节点开始去重后的所有节点,通过递归调用的方式往后面比下去,如果两个节点的值不相等,那就给从第二个开始的后面的节点去重,最后返回头节点。

关于去重,还有一种要求就是一个都不留的:[1,1,2,3,4,5,5,5]--->[2,3,4]

  /**
     * 链表去重
     * @param p     起始指针
     * @return     去重后的链表
     */
    public ListNode distinct3(final ListNode p)
    {
        if(p == null || p.getNext() == null)
        {
            return p;
        }
        if(p.getVal() == p.getNext().getVal())//如果当前节点的值等于下一个节点的值,就把下一个节点移除
        {
            ListNode temp = p.getNext();//记录下一个节点
            while (temp != null && p.getVal() == temp.getVal())//循环,直到下一个节点为空或者下一个节点的值不等于当前节点的值
            {
                p.setNext(temp.getNext());//把下一个节点移除
                temp = p.getNext();//重置下一个节点
            }
            return distinct3(p.getNext());//跳过当前节点继续往后比较
        }
        else
        {
            p.setNext(distinct3(p.getNext()));//继续往后比较
            return p;
        }


    }

这个跟上面那个递归相比,多了一while循环,用于先将有重复的几个节点间进行去重,然后,去重后还剩一个,直接返回继续往后面去重后的链表。比如1重复了,先让它只有一个1,然后递归,返回1后面的去重后端链表,1就不要了。

用非递归:
 

 /**
     * 链表去重
     * @param head  头结点
     * @return     去重后的链表
     */
    public ListNode distinct4(final ListNode head) {
        ListNode s = new ListNode(-1, head);//头哨兵
        ListNode p1 = s;
        //p2和p3用于确定重复的范围
        ListNode p2 ;
        ListNode p3 ;
        while ((p2 = p1.getNext()) != null && (p3 = p2.getNext()) != null)//循环,直到p2或p3为空
        {
            if(p2.getVal() == p3.getVal())//如果p2的值等于p3的值,就把p3移除
            {
                while (p3 != null && p2.getVal() == p3.getVal())//循环,直到p3为空或者p2的值不等于p3的值
                {
                    p3 = p3.getNext();//把p3移除
                }
                p1.setNext(p3);//把p3移除
            }
            else//如果p2的值不等于p3的值,就继续往后比较
            {
                p1 = p2;
            }
        }
        return s.getNext();
    }

很明显这里又用了哨兵,p2,p3则标记一次重复的范围,标记完了后让p1直接指向p3后面那个节点。别看这里是p1.setNext(p3) 其实这里p3已经是p3.getNext()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值