链表——删除链表中的重复元素
给定一个排序链表,删除所有重复的元素,使得每个元素只出现一次。
示例:
输入: 1->1->2->3->3
输出: 1->2->3
【解法1】单指针迭代
由于是有序链表,重复元素必相邻。因此我们可以通过比较当前结点与它之后的结点比较来确定是否重复。若重复,我们可以更改当前结点的next指针,让他跳过下一个结点,指向下一个结点之后的结点。
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode cur = head;
while(cur != null && cur.next != null){
if(cur.val == cur.next.val){
cur.next = cur.next.next;
}else{
cur = cur.next;
}
}
return head;
}
//时间复杂度O(N),空间复杂度O(1)
【解法2】递归:
- basecase:如果头结点为空或者只有一个head结点,直接返回头结点。
- 假设返回了除head外的已无重复元素的有序链表L,那么只需要判断当前head和head.next(即L的头结点)是否重复。若head的值与head.next的值不同,则整个链表都是无重复,直接返回head;若值相同,则可直接舍弃head,返回head.next。
(想递归获得了什么结果,然后关注递归后对递归结果的操作就行)
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null){
return head;
}
head.next = deleteDuplicates(head.next);
return head.val == head.next.val? head.next:head;
}
//时间复杂度O(N) 空间复杂度O(N)
【解法3】双指针
快慢指针。我们让慢指针slow在后,快指针fast在前探路,当fast找到一个不同于当前slow所指元素,就让slow前进一步,并覆盖。这样当fast结束遍历时,从头结点开始到slow指针所指的这一部分就是无重复元素链表。
(相当于slow所指的无重复区域在一步步扩散)
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode slow = head,fast = head;
while(fast != null){
if(fast.val != slow.val){
//扩大无重复区
slow.next = fast;
slow = slow.next;
}
fast = fast.next;
}
slow.next = null;//断开slow后面的链接
return head;
}
//时间复杂度O(N),空间复杂度O(1)