题目描述:Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list.
For example,
Given 1->2->3->3->4->4->5
, return 1->2->5
.
Given 1->1->1->2->3
, return 2->3
.
这题对我来说挺难的,我弄了一晚上。总是理不顺。修修补补的。哎呀,上学学的都浮于表面。遇到题目就不会了。纠结了好久,上来就重复的话,得删掉头指针,怎么删。这个想了好久。
我测试了{1,1,1,2,2,3,4} 这类长的链表,都没有问题。一旦输入 {1,2}, {1} ,{1,1},{1,2,3},{1,2,2} 这几种极端的链表。我几乎每次都报Submission Result: Wrong Answer. 修改了好久。做这种题目,极端情况一定得考虑清楚。要想的周全,经得起考验。
========
我发现,同样的代码,在intellij里不报编译的错误,而在leetcode里却报错java.lang.NullPointerException,大概是leetcode更严格吧。
我的被leetcode接受的代码,写的很复杂。完全是自己磨啊磨出来的。有时间我一定要到网上看看其他人的写法。
我的想法就是:
增加一个头结点headnew,然后指向原有的链表。这样防止一上来就是{1,1,1,2}这样的,丢失头结点。这个结点不动,一直放在那,用于输出。
增加一个标志deleteflag,记录相同的数列里的第一个数要不要删掉。
增加一个游标index,移动着删除相同数据的结点。
代码如下,我测试过没问题。如果你觉得有问题,请告诉我一下。
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public ListNode deleteDuplicates(ListNode head) { ListNode index=new ListNode(0); ListNode headnew=new ListNode(0); index.next=head; headnew=index; boolean deleteflag=false; if(head==null) return null; if(head.next==null) return head; while(index!=null){ if(index.next.next==null&&deleteflag==false) return headnew.next; if(index.next.next==null&&deleteflag==true){ index.next=null; return headnew.next; } if(index.next.val==index.next.next.val){ deleteflag=true;//记得要删除相同序列的第一个数 index.next.next=index.next.next.next; } else{ if(deleteflag==true){ index.next=index.next.next; } else { index=index.next; } deleteflag=false; //当找到不相同的数时,这个标志就要复原成false } } return headnew.next; } }测试代码
public static void main(String[] args) { removeduplicatelist r = new removeduplicatelist(); ListNode L = new ListNode(1); L.next = new ListNode(2); L.next.next = new ListNode(2); /* L.next.next.next = new ListNode(2); L.next.next.next.next = new ListNode(2); L.next.next.next.next.next = new ListNode(4); L.next.next.next.next.next.next = new ListNode(5); L.next.next.next.next.next.next.next = new ListNode(6); */ //print original string ListNode temp = new ListNode(0); temp = L; while (temp != null) { System.out.print(temp.val + " "); temp = temp.next; } System.out.println("\n"); L = r.deleteDuplicate2(L); while (L != null) { System.out.print(L.val + " "); L = L.next; } }
这个特别搞脑子,我脑子转的慢极了。所以写的非常复杂。如果您有更好的代码。恳请留言告诉我。我很乐意学习。
在网上找到牛人的代码一款:
public class Solution { public ListNode deleteDuplicates(ListNode head) { if(head == null || head.next == null) return head; ListNode dummy = new ListNode(0); dummy.next = head; head = dummy; while (head.next != null && head.next.next != null) { if (head.next.val == head.next.next.val) { int val = head.next.val; while (head.next != null && head.next.val == val) { head.next = head.next.next; } } else { head = head.next; } } return dummy.next; } }
另一款牛人的代码:
只是这里要把出现重复的元素全部删除。其实道理还是一样,只是现在要把前驱指针指向上一个不重复的元素中,如果找到不重复元素,则把前驱指针知道该元素,否则删除此元素。算法只需要一遍扫描,时间复杂度是O(n),空间只需要几个辅助指针,是O(1)。代码如下:
- public ListNode deleteDuplicates(ListNode head) {
- if(head == null)
- return head;
- ListNode helper = new ListNode(0);
- helper.next = head;
- ListNode pre = helper;
- ListNode cur = head;
- while(cur!=null)
- {
- while(cur.next!=null && pre.next.val==cur.next.val)
- {
- cur = cur.next;
- }
- if(pre.next==cur)
- {
- pre = pre.next;
- }
- else
- {
- pre.next = cur.next;
- }
- cur = cur.next;
- }
- return helper.next;
- }
可以看到,上述代码中我们创建了一个辅助的头指针,是为了修改链表头的方便。前面介绍过,一般会改到链表头的题目就会需要一个辅助指针,是比较常见的技巧。
只是我怎么没想到利用前驱指针。。。。。。。呜呜呜呜