将有序链表中重复出现的元素删除。

题目

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字。

 示例 1:

 输入: 1->2->3->3->4->4->5
 输出: 1->2->5

示例 2:

输入: 1->1->1->2->3
输出: 2->3

题解

方法一:

比较笨的方法:利用哈希表记录每个值得频率

  • 遍历链表,将每个节点的值放到哈希表中,哈希表的key就是节点的值,value是这个值出现的频率
  • 遍历哈希表,将所有频率==1的key放到集合中
  • 对集合进行排序
  • 遍历集合,然后不断创建新的链表节点

当然这里可以优化一下,比如使用LinkedHashMap或者OrderedDict这样的数据结构,可以省去排序环节。

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def createLink_rearinsert(lista):
head = ListNode(-1)
rear = head
for i in lista:
new_node=ListNode(i)
rear.next=new_node
rear=new_node
return head.next
class Solution():
def deleteDuplicates(self, head):
if not (head and head.next):
return head
# 用哈希表记录每个节点值的出现频率
d = dict()
p = head
arr = []
while p:
val = p.val
d[val] = d.setdefault(val,0)+1
p = p.next
# 将所有只出现一次的值放到arr中,之后再对这个arr排序
for k in d:
if d[k]==1:
arr.append(k)
arr = sorted(arr)
dummy = ListNode(-1)
p = dummy
# 创建长度为len(arr)长度的链表,依次将arr中的值赋给每个链表节点
for i in arr:
tmp = ListNode(i)
p.next = tmp
p = p.next
return dummy.next
if __name__=="__main__":
a=[-1,1,1,2,4]
new_a=createLink_rearinsert(a)
a1 = Solution()
p=a1.deleteDuplicates(new_a)
list1=[]
while(p!=None):
list1.append(p.val)
#print(p.val)
p=p.next
print(list1)
[-1, 2, 4]

方法二

双指针的方式,定义a,b两个指针。
考虑到一些边界条件,比如1->1->1->2这种情况,需要把开头的几个1给去掉,我们增加一个哑结点,方便边界处理。
初始的两个指针如下:

将a指针指向哑结点
将b指针指向head(哑结点的下一个节点)
如果a指向的值不等于b指向的值,则两个指针都前进一位
否则,就单独移动b,b不断往前走,直到a指向的值不等于b指向的值。

注意,这里不是直接比较a.val==b.val,这么比较不对,因为初始的时候,a指向的是哑结点,所以比较逻辑应该是这样:
a.next.val == b.next.val
当两个指针指向的值相等时,b不断往前移动,这里是通过一个while循环判断的,因为要过滤掉1->2->2->2->3重复的2。
那么整个逻辑就是两个while,但时间复杂度不是O(N^2),而是O(N),空间上也只是常数级别。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def createLink_rearinsert(lista):
head = ListNode(-1)
rear = head
for i in lista:
new_node=ListNode(i)
rear.next=new_node
rear=new_node
return head.next
class Solution(object):
def deleteDuplicates(self, head):
if not (head and head.next):
return head
dummy = ListNode(-1)
dummy.next = head
a = dummy
b = head
while b and b.next:
# 初始化的时a指向的是哑结点,所以比较逻辑应该是a的下一个节点和b的下一个节点
if a.next.val!=b.next.val:
a = a.next
b = b.next
else:
# 如果a、b指向的节点值相等,就不断移动b,直到a、b指向的值不相等
while b and b.next and a.next.val==b.next.val:
b = b.next
a.next = b.next
b = b.next
return dummy.next

if __name__=="__main__":
a=[-1,1,1,2,4]
new_a=createLink_rearinsert(a)
a1 = Solution()
p=a1.deleteDuplicates(new_a)
list1=[]
while(p!=None):
list1.append(p.val)
#print(p.val)
p=p.next
print(list1)
[-1, 2, 4]

方法3:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def createLink_rearinsert(lista):
head = ListNode(-1)
rear = head
for i in lista:
new_node=ListNode(i)
rear.next=new_node
rear=new_node
return head.next
class Solution(object):
def deleteDuplicates(self, head):
if not (head and head.next):
return head
dummy = ListNode(-1)
dummy.next = head
a = dummy
b = head.next
while b:
if a.next.val!=b.val:
a = a.next
b = b.next
else:
while b and a.next.val==b.val:
b = b.next
# 这里的去重跟解法二有点差别,解法二的是
# a.next = b.next
a.next = b
# b指针在while中判断完后,可能指向了null,这里需要处理边界问题
b = b.next if b else None
return dummy.next

if __name__=="__main__":
a=[-1,1,1,2,4]
new_a=createLink_rearinsert(a)
a1 = Solution()
p=a1.deleteDuplicates(new_a)
list1=[]
while(p!=None):
list1.append(p.val)
#print(p.val)
p=p.next
print(list1)
[-1, 2, 4]