- 题目描述
给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有重复出现的数字。
来源:LeetCode
- 示例
- 示例 1:
输入: 1->2->3->3->4->4->5
输出: 1->2->5 - 示例 2:
输入: 1->1->1->2->3
输出: 2->3
- 思路分析
- 本题和#83有点相像,但本题仅保存没有重复出现的元素。相比于#83,头节点和尾节点需要特殊考虑,以及新链表的头节点确定相对比较麻烦。
- 因为链表是有序的,那么很容易判断一个元素是否重复。我们定义
t
e
m
p
temp
temp和
h
e
a
d
head
head,令
h
e
a
d
=
t
e
m
p
.
n
e
x
t
head = temp.next
head=temp.next。然后比较
t
e
m
p
.
v
a
l
,
h
e
a
d
.
v
a
l
,
h
e
a
d
.
n
e
x
t
.
v
a
l
temp.val, head.val, head.next.val
temp.val,head.val,head.next.val。注意我们比较这三个数,仅仅是为了确定head能否加入新链表;
t
e
m
p
temp
temp是已经考虑过的元素,不用管。
①如果满足 t e m p . v a l < h e a d . v a l < h e a d . n e x t . v a l temp.val<head.val<head.next.val temp.val<head.val<head.next.val,说明 h e a d head head没有重复,可以加入新链表。
②如果不满足,说明 h e a d head head一定重复,可能和 t e m p temp temp重复,可能和 h e a d . n e x t head.next head.next重复,也可能三个节点值相等。如果 t e m p temp temp和 h e a d head head重复,我们就知道 h e a d head head不可能加入链表,就改变 t e m p temp temp指向 h e a d head head, h e a d head head指向 h e a d . n e x t head.next head.next,然后同样判断 h e a d head head;如果是 h e a d head head和 h e a d . n e x t head.next head.next重复,说明这两个元素都不可能加入链表,因此需要判断的是 h e a d . n e x t . n e x t head.next.next head.next.next,因此令 h e a d head head指向 h e a d . n e x t . n e x t head.next.next head.next.next,而 t e m p temp temp仍然指向新 h e a d head head的前一位,即改变之前的 h e a d . n e x t head.next head.next。 - 原链表头节点的特殊处理:因为头节点没有 t e m p temp temp,因此我给原链表加上一个值为 h e a d . v a l − 1 head.val-1 head.val−1的节点作为新头节点,然后令 t e m p temp temp指向新的头节点,这样可以判断 h e a d head head是否重复。
- 原链表尾节点的特殊处理:当退出循环后,说明已经到了链表的结尾。此时有两种可能:
① h e a d = = n u l l head == null head==null: t e m p temp temp指向最后一位, h e a d head head为空。那么前面找到的链表就是最终结果,因为我们不考虑 t e m p temp temp,仅考虑 h e a d head head。
② h e a d . n e x t = = n u l l head.next == null head.next==null: t e m p temp temp指向链表的倒数第二个元素, h e a d head head指向链表的最后一个元素。此时如果两个节点值相等,前面找到的链表就是最终结果;如果两个节点的值不相等,那么需要将 h e a d head head加入链表。 - 新的头节点:新的头节点有可能不存在,此时所有的元素都重复。
①如何确定新链表的头节点?如果存在,即为第一个不重复的元素值。此时即体现出了将 n e w H e a d newHead newHead的初始值设为 h e a d . v a l u e − 1 head.value-1 head.value−1的原因:保证这个值是唯一的。当找到一个不重复元素,如果此时 n e w H e a d newHead newHead的值是 h e a d . v a l u e − 1 head.value-1 head.value−1,我们就知道这个元素应该作为新链表的头节点。
②处理尾节点时,要记住此时头节点可能为空。
- JAVA实现
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
if(head == null || head.next == null) return head;
ListNode temp = new ListNode(head.val-1); //在最前面添加一个头
temp.next = head;
int value = head.val; //当head改变,head.val也会变,因此先保存成常量
ListNode newHead = new ListNode(value-1);
ListNode hold = newHead;
//比较三个连续的数,temp, head, head.next
//iff temp.val<head.val<head.next.val, head可以保留在链表中
//if temp.val == head.val, 说明head不能留,将temp和head分别后移一位
//if head.val == temp.val, 说明head和temp都不能留,将temp指向head.next,head指向temp.next
while(temp!=null && head!=null && head.next!=null) {
if(head.val > temp.val && head.val < head.next.val) {
if(newHead.val == value-1) {
newHead = head;
hold = newHead;
}
else {
hold.next = head;
hold = hold.next;
}
temp = head;
head = head.next;
}
else {
if(temp.val == head.val) temp = head;
else if(head.val == head.next.val) temp = head.next;
head = temp.next;
}
}
if(head == null) { //temp是最后一位,head是空
if(newHead.val == value-1) return head; //没有满足条件的
else {
hold.next = head;
return newHead;
}
}
//temp是倒数第二位,head是最后一位的情况
if(temp.val != head.val) { //值不相等,添加head
if(newHead.val == value-1) return head;
else hold.next = head;
}
else { //值相等
temp = head.next;
if(newHead.val == value-1) return temp;
else hold.next = temp;
}
return newHead;
}
}