1.单链表操作
class ListNode: def __init__(self,data): #data为数据项,next指向下一节点 self.data = data self.next = None class LinkList: def __init__(self): #初始化head指针 self.head = None #创建链表 def initList(self,data): self.head = ListNode(data[0]) cur = self.head for val in data[1:]: node = ListNode(val) cur.next = node cur = cur.next return self.head #打印链表 def printList(self): if self.head == None:return cur = self.head while cur: print(cur.data,'->',end='') cur = cur.next #查找某元素 def findKth(self,e): temp = self.head while temp: if temp.data == e: return temp temp = temp.next return None #将元素element插入到e元素后 def insertK(self,e,element): Node = ListNode(element) p = self.findKth(e) if p == None:return temp = p.next p.next = Node Node.next = temp return self.head #删除某元素 def remove(self,e): cur = self.head pre = None while cur: if cur.data == e: #找到了指定元素 if not pre: #如果为头结点 self.head = cur.next else: pre.next = cur.next break else: pre = cur cur = cur.next
2.链表反转
2.1 反转一个单链表
力扣206题:https://leetcode-cn.com/problems/reverse-linked-list/
def reverselist(self,head): #递归结束的条件 if head == None or head.next == None: return head p = self.reverselist(head.next) head.next.next = head head.next = None return p
在链表的题型中,一定要注意的是各个指针所指向的链表中的位置,函数一般返回的都是头节点。一般只要搞清楚指针的具体指向以及在函数中的变化,链表问题一般都能看懂。
head 指向 1,在递归后,头节点后的链表实现了反转,这时 p 指针指向原链表中的最后一个节点,也即是 4。根据图示,接下来要做的就是将位节点2(head.next)的下一个指针指向 节点1 (head),并将原链表的头节点指向None,因此需要head.next.next = head,以及head.next = None。接下来需要返回结果链表的头节点,也即是p即可。
非递归:
def reverselist(self,head): pre = None cur = head while cur: p = cur.next cur.next = pre pre = cur cur = p return pre
2.2 反转链表前N个节点
#递归 def reverseN(self, head, n): if n == 1: return head p = self.reverseN(head.next, n-1) successor = head.next.next head.next.next = head head.next = successor return p #非递归 def reverseN(self, head, n): if n == 1: return head pre = None cur = head count = 0 while count != n: p = cur.next cur.next = pre pre = cur cur = p count += 1 head.next = p return pre
2.3 反转链表的m到n个节点
力扣92:https://leetcode-cn.com/problems/reverse-linked-list-ii/
def reverseMtoN(self, head, m, n): if m == 1: return self.reverseN(head,n) head.next = self.reverseMtoN(head.next, m-1,n-1) return head # 方法2 def reverseMtoN(self, head, m, n): if m == 1: return self.reverseN(head, n) cur = head pre = None count = 1 while count != m: pre = cur cur = cur.next count += 1 p = self.reverseN(cur, n - m + 1) pre.next = p return head # 返回的总是头节点
2.4 每k个一组对链表进行翻转,如果节点总数不是k的倍数,则将最后剩余的节点保持原有顺序
力扣25:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
def reverseK(self,head,k): i = 1 temp = head while i < k and temp != None: temp = temp.next i += 1 if temp == None: return head t2 = temp.next temp.next = None Newhead = self.reverseList(head) #要想利用反转链表这个函数,只需要将链表每k个元素用None截断 Newtemp = self.reverseK(t2,k) head.next = Newtemp return Newhead
2.5 每k个一组对链表进行从后往前翻转,如果节点总数不是k的倍数,则将最后剩余的节点保持原有顺序
def RevReverK(self,head,k): p = self.reverseList(head) q = self.reverseK(p,k) return self.reverseList(q)
3. 快慢指针在链表中的应用
3.1 删除链表中的倒数第n个节点
力扣19:https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/
快慢指针的前进方向是一致的,但前进的步伐不同,快指针较快,具体快指针比慢指针快多少,要根据实际问题进行分析。
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode: #快指针先走几步,可以从结束条件开始考虑,快指针先走k-1步,这样当快指针走到最后时,慢指针指向k slow = head fast = head count = 0 while count < n-1: fast = fast.next count += 1 if fast.next == None: return head.next while fast.next: temp = slow slow = slow.next fast = fast.next temp.next = slow.next return head
3.2 环形链表
力扣:https://leetcode-cn.com/problems/linked-list-cycle/
def hasCycle(self, head: ListNode) -> bool: if head == None or head.next == None: return False slow = head fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False
快指针比慢指针多走一步,若链表中存在环,当快指针比慢指针多走一个环时,二者就会相遇。
3.3 相交链表
力扣160:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode: if headA == None or headB == None: return None pA = headA pB = headB while pA != pB: pA = pA.next if pA else headB pB = pB.next if pB else headA return pA
4.用环形链表解决约瑟夫环问题
问题描述:编号为1-N的N个士兵围坐在一起形成一个圆圈,从编号为1的士兵开始依次报数,数到m的士兵会被杀死出列,之后的士兵再从1开始报数。直到剩下最后一个士兵,求这个士兵的编号。
#约瑟夫环问题 class ListNode: def __init__(self, x): self.val = x self.next = None class LinkList: def __init__(self): self.head = None #构建环形链表 def circleList(self,N): self.head = ListNode(1) r = self.head cur = self.head for i in range(2,N+1): node = ListNode(i) cur.next = node cur = cur.next cur.next = r return r def Josephus(self,N,m): if N < 2 or m == 1: return N head = self.circleList(N) p = head while p.next != p: for i in range(m-1): pre = p p = p.next pre.next = p.next p = pre.next return p.val
这种方法的时间复杂度为O(N*m),空间复杂度为O(N),还可利用递归来解决,感兴趣的可以自行百度。