链表8:链表中环的入口结点

来源:互联网 发布:039什么意思网络用语 编辑:程序博客网 时间:2024/06/05 08:46

题目:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

思路:所谓删除结点node只需要将node前面结点的next指针直接指向node结点的下一个结点即可,不需要将node置null或者将node的next属性置为null,因为被删除结点由于不再被上一个结点引用,就会成为不可达的死对象从而会被GC自动回收。

这里关键是如何判断重复结点,并且将指针指向下一个不重复的结点;判断连续的重复很复杂:

这道题目较复杂,关键是对于几种特殊类型的全面考虑,即便捷情况的考虑:

pnext为null怎么办?

如果是pcur的第一个pnext指针为null,表示为1233445这种情况,即最后一个结点没有重复;即pcur是没有重复的结点,且是最后一个结点,此时对应情形①。于是将pcur连接到retainedNode后面然后返回dummy链表即可。

如果是在pnext对重复的多个结点进行移动时出现pnext为null,表示为12334555这种情况,即最后的结点重复,此时对应情形②,由于不会再有新的结点出现了,而最后一个结点又不是单独的结点,因此所有工作已经结束了,可以直接结束循环返回dummy链表,如果不及时返回会进入情况①的else模块中,导致retainedNode又被附上了pcur的值,而pcur实际上是重复值!

情况③是普通的情况,即用来寻找不重复的结点。即要有一个指针pnext来遍历判断后面的几个结点是否是重复的,如果有重复就向下移动,直到有不重复的结点,将它作为新的pcur,并将它连接到retainedNode链表上面。

/* public class ListNode {    int val;    ListNode next = null;    ListNode(int val) {        this.val = val;    }}*/// 该方法用来删除链表中重复的结点,最终返回的链表中没有重复的结点1223445-->135public ListNode deleteDuplication(ListNode pHead) {// 特殊的输入if (pHead == null)  return null;// 由于需要构造返回一条新的链表,因此使用固定技巧ListNode dummy = new ListNode(-1);// 保留下来的结点组成的链表ListNode retainedNode = dummy;// 当前正在判断是否重复的结点ListNode pcur = pHead;// 找准确循环条件究竟是什么,这里是对每个当前结点进行遍历:先pcur!=null,再求出pcur的next结点while (pcur != null) {// 当前结点之后的结点,需要逐个与pcur进行比较ListNode pnext = pcur.next;/*** pcur之后的值与他相同,pcur必然是重复结点,还需要将重复部分全部遍历完 共有几种情况:* 1.pnext是null,表示pcur是最后一个结点; 2.pnext!=null但是pcur.val ==pnext.val表示下一个结点与pcur重复; 3.pnext!=null但是pcur的下一个值与他不同,表示pcur是一个不重复的点;每种情况要分别处理。*/if (pnext != null && pcur.val == pnext.val) {while (pnext != null && pcur.val == pnext.val) {// pnext指针不断向下移动pnext = pnext.next;//情况③}// 当pnext指针不再往下移动时有两种情况:1.pnext为null;2.此时pnext终于不再是重复值了,是一个新的值,分别处理。// 如果pnext为null,那么表示是尾部相同的数例如123444,应该立即结束循环返回,否则会进入12333445的else模块,这两种情形是不同的。if (pnext != null) {    pcur = pnext;pnext = pcur.next;} else {            //情况②return dummy.next;}} else if (pnext != null && pcur.val != pnext.val) {// 如果pcur之后的值与pcur就不同,那么说明pcur是唯一的,不重复,需要保留//特别注意:要把pcur结点连接到retainedNode时,需要先将pcur后面的结点关系切断,否则如果pcur是retainedNode上面的最后一个结点,那么会把pcur后面所跟的结点全部带到retainedNode链表中来;例如12233455可能会得到1455,因为当4被连接到retainedNode上面时会将55也带着。pcur.next = null;retainedNode.next = pcur;retainedNode = retainedNode.next;// 此时也需要向下推进,判断下一个结点是否重复pcur = pnext;pnext = pcur.next;} else {// 即此时pnext==null,说明pcur已经是最后一个结点了,这个结点必然是不重复的结点,即最后一个结点是一个单独的结点,例如12333445 //情形①retainedNode.next = pcur;retainedNode = retainedNode.next;return dummy.next;}}return dummy.next;}}


别人的简洁代码:再理解public static ListNode deleteDuplication(ListNode pHead) {                 ListNode first = new ListNode(-1);//设置一个trick         first.next = pHead;         ListNode p = pHead;        ListNode last = first;        while (p != null && p.next != null) {            if (p.val == p.next.val) {                int val = p.val;                while (p!= null&&p.val == val)                    p = p.next;                last.next = p;            } else {                last = p;                p = p.next;            }        }        return first.next;}



0 0
原创粉丝点击