6月5号的题目是一道链表题,非常简单,但是却可以显示出链表题目做法的相关思路,这边是先要推荐一个blog照着这个人的博客练习效果非常不错。
然后是一贯的一开始的tip:哑节点和指针:tmp和res指向的是存储 哑节点0 的位置,此时tmp和res存储的是同一内存地址,可以理解成tmp和res是两个指针。当对res进行操作时,会在res中存储内容(节点)即为这个内存放内容。而res不断移动,tmp还是指向原来的 哑节点的位置。
特别提醒:
#在python里面移动两个节点的公式:
while p.next and p.next.next:
p = p.next.next
题目:第一类,python删除题目:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
dummy = ListNode(0)#建立哑节点
dummy.next = head
#双指针问题
#两个指针差n个距离
left = dummy
right = left
for i in range(n):
right=right.next
while right.next:
left=left.next
right=right.next
tmp = left.next.next
left.next=tmp
return dummy.next
这道题目一次遍历需要用到双指针和哑节点:注意最后的return dummy.next 可以很好地处理边界情况。
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
dummy = ListNode(0)
# if l1.val>l2.val:
# dummy.next=l1
# else: dummy.next=l2
q=dummy
p1,p2 = l1,l2
while p1 and p2:
if p1.val<p2.val:
q.next = p1
p1=p1.next
else:
q.next=p2
p2=p2.next
q=q.next
if p1: q.next=p1
else: q.next=p2
return dummy.next
哑节点做,本质上是一个插入题
接下来,来做这个题目的进阶版本
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
def delete(lists):
del_list= []
for idx,node in enumerate(lists):
if node:
del_list.append(node)
return del_list
dummy = ListNode(0)
q = dummy
lists = delete(lists)
while lists:
min_idx,minnode = 0, lists[0]
for idx,node in enumerate(lists):
if node.val < minnode.val:
minnode = node
min_idx=idx
q.next = minnode
lists[min_idx] = lists[min_idx].next
q=q.next
lists = delete(lists)
return dummy.next
这里是一开始的思路,但是超时间了,主要的问题是找最小用时太多了,这个时候最快的方法是动态维护一个堆结构
这里应该是一个小顶堆,关于小顶堆的构建我们用最经典的自下而上建堆,建堆时间复杂度为O(N), siftdown操作的时间复杂度为logn
def sift(li,low,high):
i = low
j= 2*i+1
tmp = li[i]
while j<=high:
if j+1<=high and li[j+1]<li[j]:
j=j+1
if li[j]<tmp:
li[i] = li[j]
i = j
j=2*j+1
else:
break
li[i] = tmp
def heap_sort(li,k):
#构建小顶堆
n= len(li)
for i in range(n//2-1,-1,-1):
sift(li,i,n-1)
topk=[]
for i in range(k):
topk.append(li[0])
li[0] = li[-1]
li.pop()
sift(li,0,len(li)-1)
return topk
这里我首先是要先弄懂堆的原理,然后用python里自带的优先队列 module heapq,在heapq的使用中最重要的一点是要注意heapq的优先级,关于这个python3 cookbook 1.4有着非常清晰的讲解。
from heapq import *
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
heap=[]
#首先先建立一个堆
for idx,node in enumerate(lists):
if node:
heappush(heap,(node.val,idx,node))
#lists[idx] = lists[idx].next
dummy = ListNode(0)
q = dummy
while heap:
_ ,idx,cur = heappop(heap)
q.next=cur
q=q.next
if cur.next:
heappush(heap,(cur.next.val,idx,cur.next))
return dummy.next
稍微熟悉了一下heapq的操作。今天就这样吧