这一篇是LeetCode上关于链表的两道题目,难度都是中等,但是我认为难度很大了,尤其是复制链表一题,思路清奇。
1)82. Remove Duplicates from Sorted List II (从有序列表中移除重复项)
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.
要注意83题是保留一项,十分简单,就不解析了;而这道题威力加强,如果有两项是重复的,就全都删掉。先看代码再解释:
# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val = x # self.next = None class Solution: def deleteDuplicates(self, head): """ :type head: ListNode :rtype: ListNode """ if head == None or head.next == None: return head fhead = ListNode(0) fhead.next = head pre = fhead cur = head while cur: while cur.next and cur.val==cur.next.val: cur = cur.next if pre.next == cur: # 如果只此一个值,不删除,pre后移 pre = cur else: pre.next = cur.next # 如果不只一个,删除这些结点,pre暂不后移 cur = cur.next return fhead.next
因为头结点可能会被删掉,先加一个结点;判断相邻两项的值,停留在重复项的最后一个位置(或者就原地不动了),通过pre指针与当前指针的关系判断两种情况。理解解题思想很关键~
2)138. Copy List with Random Pointer(复制含有随机指针的链表)
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
这一链表结点的定义看下面代码,这一题其实蛮有难度,甚至题目还如此简洁,连个样例都没有,测试样例也看不懂。复制问题的关键在于,挨个复制结点时,结点的next本身复制了结点间的连接关系并赋予label值,创建了一个label和next属性都一样的新结点,而random指向另一结点时,却不能通过复制label来解决,因为其指向一个已存在的结点(该链表中的),你复制的话就分叉了而没有指向该链表中的结点(或者指向了原链表中的结点)。
下面的解决方案有点牛逼,看后面的大神的方法写的:
# Definition for singly-linked list with a random pointer. # class RandomListNode(object): # def __init__(self, x): # self.label = x # self.next = None # self.random = None class Solution(object): def copyRandomList(self, head): """ :type head: RandomListNode :rtype: RandomListNode """ if head == None: return None p = head while p: tmp = p.next p.next = RandomListNode(p.label) p.next.next = tmp p = tmp p = head while p: if p.random: p.next.random = p.random.next p = p.next.next newhead = RandomListNode(0) p = head q = newhead while p: tmp = p.next.next q.next = p.next q = q.next p.next = tmp p = tmp return newhead.next
这一方法用了三次循环,结合下图理解一下。该方法的时间复杂度为O(n),空间复杂度O(1),几乎不占用额外的内存空间。
当然这一问题有一个更直观的解决方法,就是哈希表,第一次遍历存储各结点,第二遍设置随机指针,其空间复杂度为O(n).
python语言中用字典也可以解决这个问题,详情可看如下代码:
class Solution: # @param head, a RandomListNode # @return a RandomListNode def copyRandomList(self, head): dic = collections.defaultdict(lambda: RandomListNode(0)) dic[None] = None n = head while n: dic[n].label = n.label dic[n].next = dic[n.next] dic[n].random = dic[n.random] n = n.next return dic[head]