链表问题整理

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),还可利用递归来解决,感兴趣的可以自行百度。

 

posted @ 2020-06-15 19:51  清洺  阅读(152)  评论(0编辑  收藏  举报