第 2天
链表(简单)
没什么可说的,直接上代码
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
num_list = []
while head:
num_list.append(head.val)
head = head.next
num_list.reverse()
return num_list
先上代码
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
num_list = []
while head != None:
num_list.append(head.val)
head = head.next
num_list.reverse()
tem_head = ListNode()
tem = tem_head
for i in range(len(num_list)):
tem.next = ListNode(num_list[i])
tem = tem.next
return tem_head.next
刷题心得:
此题在第一问的基础上做了延伸,我的思路,先利用第一问的List,在构造一个心得Linklist,将List中的元素倒叙一个一个加入Linklist。
当然又一点问题就是新链表的头元素,如果我们直接将List最后一个元素付给链表头,当输入List = [] 时,返回值为Null 实际应为[],系统报错。
这里我们使用伪头节点,最后return tem_head.next返回真正链表即可。
这里List也可用Stack替代,就不需要反转列表了。
当然也有不用中间List的思路,不过上面是最容易想到的。
下面是不用List的双指针方法:
- 设置两个指针,cur 指向链表头节点,pre 指向空
- 暂存 cur 的后继节点,tmp = cur.next
- 将 cur.next 反指向pre
- 将 pre 指向 cur,即 pre 指针后移
- 将 cur 指向 2 中暂存的 tmp 节点,即 cur 指针后移 循环 第2 到 5 步,直到 cur 遍历完整个链表
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
cur = head
pre = None
while cur:
tem = cur.next
cur.next = pre
pre = cur
cur = tem
return pre
说实话第三题有点离谱,可能是我基本功不够的原因,明知道是DeepCopy依然return head,哈哈哈哈,然后我的思路很奇怪,先把每个节点复制一遍,用next先把链表连起来,剩下的就是把random补全。
我的想法是根据节点的val,把符合某一个节点.random.value的节点加到list,然后找出哪一个是他真正的random节点再加入true_ran_list,这个list保存着全部复制节点的index,然后根据index挨个把random补全。
以下是我的最原始代码
但是该方法时间复杂度O(n**2),且用到了很多循环,很浪费时间,但是对我这种菜鸡来说能两遍做出来就很满足了,另外还有老哥非常的幽默哈哈哈哈。
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
node_list = []
val_list = []
ran_val_list = []
while head:
node_list.append(head)
val_list.append(head.val)
if head.random:
ran_val_list.append(head.random.val)
else:
ran_val_list.append(None)
head = head.next
#print(val_list)
#new linklist node
new_node_list = []
for i in val_list:
new_node_list.append(Node(i))
#find random index
ran_index_list = []
for i in ran_val_list:
tem = []
for j in range(len(val_list)):
if i == val_list[j]:
tem.append(j)
elif i == None:
tem.append(None)
break
ran_index_list.append(tem)
#print("+++",ran_index_list)
true_ran_list = []
for i in range(len(ran_index_list)):
if len(ran_index_list[i])>=2:
for j in ran_index_list[i]:
if node_list[i].random == node_list[j]:
true_ran_list.append(j)
else:
true_ran_list.append(ran_index_list[i][0])
#print("true:",true_ran_list)
#add next and random
new_head = Node(0)
cur = new_head
for i in range(len(node_list)):
#next
cur.next = new_node_list[i]
#random
if true_ran_list[i] != None:
cur.next.random = new_node_list[true_ran_list[i]]
else:
cur.next.random = None
cur = cur.next
cur.next = None
return new_head.next
哈希表法
这个方法很精妙,先用字典存储原node(key)和新node(value),接下来使用map将dic key中的next,random一一对应到dic value中
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if head == None:
return None
nodeDict = {}
node = head
while node:
nodeDict[node] = Node(node.val)
node = node.next
l = head
while l:
nodeDict[l].next = nodeDict.get(l.next)
nodeDict[l].random = nodeDict.get(l.random)
l = l.next
return nodeDict[head]
这里涉及了一个知识点:
get() 方法 Vs dict[key] 访问元素区别
get(key) 方法在 key(键)不在字典中时,可以返回默认值 None 或者设置的默认值。
dict[key] 在 key(键)不在字典中时,会触发 KeyError 异常。
所以尽量使用get()方法,避免报错
原地算法
思路:
1:复制每一个结点,并且使复制的结点在原结点的后面,实现从1->2->3->null, 变成1->1->2->2->3->3->null
2:复制random指针,注意判断random是否为null
3:将复制完成的结点一分为二,注意还要将原来的链表还原回去
class Solution:
def copyRandomList(self, head: 'Node') -> 'Node':
if head == None:
return None
node = head
while node != None: # 首先复制一遍链表
new = Node(node.val)
temp = node.next
node.next = new
new.next = temp
node = node.next.next
node = head # 然后给复制的节点加上random引用
while node != None:
node2 = node.next
if node.random != None:
node2.random = node.random.next
node = node.next.next
# 最后拆开复制的链表
node, node2 = head, head.next
ans = node2
while node.next != None and node2.next != None:
node.next = node.next.next
node2.next = node2.next.next
node = node.next
node2 = node2.next
return ans