This paper will introduce the basic disintegration ideas and classic problems of linked list algorithm. This paper not only pursues to write excellent linked list code, but also cares more about how to write bug-free linked list code within a limited time.

General ideas for solving linked list problems:

A linked list is a linear storage structure that uses discrete memory blocks and stores Pointers to the next memory block in each memory. Therefore, a linked list is a form of a linear list. Linked list problem is a kind of problem to investigate the basic coding ability. The characteristic of this kind of problem is that the solution is not complicated, but the difficulty is to prove the correctness of the solution and how to code. That is, to see if you can write bug-free code, and to see if you can prove the algorithm mathematically.

  • Use graphic techniques to free up some brain space. Think about the problem by drawing several small-scale examples. If the problem requires more than three Pointers to solve, then the time cost of drawing is acceptable.
  • By drawing a general case, think about the main body disintegration of the algorithm. Usually 3-5 nodes.
  • In this case, it is more important not to code immediately, but to give a few special examples to verify that the general idea is robust in special scenarios, usually 0,1,2,3,4 linked list nodes, and whether the list Pointers at the head and tail nodes work properly.
  • Must be patient, do not try to fast and submit code, linked list problem is to exercise your code review ability, the idea is very simple, the difficulty is to bear down, calm analysis. Trust me, you can always find the problem with the first code.

So what’s the general idea? This is a model, linked list problem algorithm ideas is so several, after the master can apply, mathematical proof to see a few typical cases, the real difficulty lies in coding, linked list problem is related to pointer operation, easy to make mistakes, write bug free is very not allow things, so the most important is to practice more.

Classical linked list problems:

  1. Design a singly linked list: This takes advantage of the sentry idea
class MyLinkedList:

    def __init__(self):
        Initializing a linked list with a sentry node that never stores data simplifies the condition reading of head and tail insertions in insert and delete operations, thus increasing speed. "" "
        self.sb = ListNode(- 1)
        self.le = 0


    def get(self, index):
        """ Gets a node in a linked list by index. "" "
        head = self.sb.next
        if  index < 0 or index >= self.le or head == None:
            return - 1
        for i in range(index):
            head = head.next
        return head.val


    def addAtHead(self, val):
        Insert node at the position of the head node, sentry mind so that it does not read the non-null case. "" "
        head = self.sb.next
        self.sb.next = ListNode(val)
        self.sb.next.next = head
        self.le += 1


    def addAtTail(self, val):
        """ Insert node at the end """
        tmp = self.sb
        for i in range(self.le):
            tmp = tmp.next
        tmp.next = ListNode(val)
        self.le += 1


    def addAtIndex(self, index, val):
        Inserts a node at the specified index.
        if  index < 0 or index > self.le :
            return - 1
        pre = self.sb
        for i in range(index):
            pre  = pre.next
        tmp = pre.next
        pre.next = ListNode(val)
        pre.next.next = tmp
        self.le += 1


    def deleteAtIndex(self, index):
        """ Specify index position to delete node """
        if index < 0 or index >= self.le:
            return
        pre = self.sb
        for  i in range(index) :
            pre = pre.next
        pre.next = pre.next.next
        self.le -= 1
Copy the code
  1. Check whether the list has rings

The classical three questions of two-pointer thought are: whether a linked list has a ring, the intersection of the list and the ring, and the length of the ring. Define two Pointers, start from the beginning, one takes 2 steps each time, the other takes one step, if the two intersect, there will be a ring, do not cross the pointer that takes two steps first to the tail, then the interpretation of acyclic.

class Solution(object):
    def hasCycle(self, head):
        if head is None or head.next is None:
            return False
        fast ,slow = head,head
        while fast is not  None and fast.next is not None:
            fast = fast.next.next
            slow = slow.next
            if slow == fast:
                return True
        return False
Copy the code
  1. Determine the entry point of the ring

After the fast and slow Pointers meet, the fast Pointers point to the head node again, and the two Pointers start to move simultaneously, one step at a time. When they meet again, they are the entry points of the rings.


class Solution(object):
    def detectCycle(self, head):
        if head == None or head.next == None:
            return None
        fast = head.next.next
        slow = head.next
        whilefast ! =None andfast.next ! =None:
            fast = fast.next.next
            slow = slow.next
            if fast == slow:
                break
        if fast == None or fast.next == None:
            return None
        fast = head
        whilefast ! = slow: fast = fast.next slow = slow.nextreturn fast
Copy the code
  1. Solve the length of the ring to find the meeting point, one pointer continues to move, each step, record the number of moves, the other pointer does not move, the number of encounters is the length. It’s easy. Imagine.
  pass
Copy the code

So the question is, are the first two algorithms correct, and how do you prove them mathematically? 1. When the slow pointer reaches the entry point of the ring,L1 represents the distance from head to the entry point, which is also the distance traveled by the slow pointer. This means that the fast pointer must reach the entry point of the ring, and the distance from the entry point is set as L2. I represents the number of steps that the slow pointer needs to take to catch up with the fast pointer. 3. Total steps of slow pointer of S1 code, and total steps of fast pointer of S2 code. 4. C is the circumference of the ring. If the fast and slow Pointers meet, then (S1+i-L1)mod C = (S2+2i-L1)mod C. L1 is subtracted to subtract the number of steps before entering the loop. The slow pointer followed I steps so the fast pointer actually took 2I steps. Therefore, this condition must be satisfied if the encounter is certain. After removing the influence of the number of steps before entering the ring, only the distance relative to the entry point of the ring after entering the ring can be seen as follows :S1 = L1, s2-L1 = NC + L2, where N is the number of circles already around the ring. I mod C = (NC+L2+2i) mod C = (NC+L2+2i) mod C = (L2 + I) mod C = 0,N = 0, we know that L2 < C, I must have a solution within the integer range, so the fast and slow Pointers must meet. Proof of entry point algorithm of ring: (4)=>(4)=>(m-n-1)L2+L2=s =>(M-n-1)L2+ P1+P2=L1+P1 <=> (m-n-1)L2+P2=L1 P1+P2=L2), which tells us that the length of the list excluding rings is equal to the length from the intersection to the first intersection plus the length of the rings.

  1. Find the intersection point of two lists. Two Pointers point to the heads of two lists, respectively. When you keep going forward, when you reach the tail, you return to the head of another list. The intersection of linked list, to must be short at the end of the first list, back to the long list of head, when the long list of Pointers to the end also, its length was has come a step closer to the number of nodes in the list are, as long chain table pointer back to a short list of the head, the two position alignment, the forward, eventually meet, is the intersection point.
class Solution(object):
    def getIntersectionNode(self, headA, headB):
        p1 ,p2 = headA,headB
        whilep1 ! = p2: p1 = headBif p1 == None else p1.next
            p2 = headA if p2 == None else p2.next
        return p1
Copy the code
  1. Delete the two Pointers of the NTH reciprocal node of the single linked list. One of them moves n steps first, and then the two Pointers move together. When the first pointer reaches the tail, the last pointer is the precursor node of the node to be deleted. The NTH to the last is actually the positive number L minus n plus 1,L is the length of the list, so L minus n is exactly the precursor to deleting the node. N steps, and then L-n, so that the second pointer is exactly at the L-n node.
class Solution(object):
    def removeNthFromEnd(self, head, n):
        pre ,last = head,head
        for i in range(n):
            pre = pre.next
        if pre == None:
            return head.next
        whilepre.next ! =None:
            pre = pre.next
            last = last.next
        last.next = last.next.next
        return head
Copy the code

The problem of pointer operation is to examine the boundary conditions of pointer operation, which requires coding ability.

  1. Single-linked list inversion two Pointers implementation C version:

class Solution(object):
    def reverseList(self, head):
        "" Use three Pointers to complete a single linked list operation. "" "
        if head == None:
            return None
        pre = None
        next = head.next
        whilehead ! =None:
            head.next = pre
            pre = head
            head = next
            ifnext ! =None:
                next = next.next
        return pre
Copy the code
  1. The boundary condition is considered when removing all elements with the value val in the list. The first loop is the key. The method of deleting val by traversing a list with 0,1,2, and 3 nodes is not suitable for the head nodes and the head nodes are successive Val nodes that need to be deleted.

class Solution(object):
    def removeElements(self, head, val):
        if head == None:
            return None   
        whilehead ! =None and head.val == val:
            if head.next == None:
                return None
            else:
                head = head.next
        pre = head
        whilepre.next ! =None:
            if pre.next.val == val:
                pre.next = pre.next.next
            else:
                pre = pre.next
        return head
Copy the code
  1. The parity linked list moves forward by interleaving two Pointers next to each other, skillfully realizing the independent traversal of the parity nodes, and then connecting them independently and merging them. The difficulty is that pointer relations do not make a mistake, you can use drawing skills to assist thinking, linked list problems test programming ability, to calm down, patience check this is the key.
class Solution(object):

    def oddEvenList(self, head):
        if head is None:
            return head
        odd = head
        even = head.next
        if even is None:
            return head
        odd_prev = odd
        even_prev = even
        even_head = even
        while even is not None and even.next is not None:
            odd = even.next
            even = odd.next
            odd_prev.next = odd
            even_prev.next = even
            odd_prev = odd
            even_prev = even
        odd.next = even_head
        return head
Copy the code
  1. The fast and slow pointer of palindrome list finds the midpoint, reverses the second half of the list, traverses the list from the beginning to the midpoint again, and compares its value one by one to judge the palindrome. The emphasis here is on proper abstraction in the coding process, which can simplify the code logic and greatly improve the correctness and readability of the written code.
class Solution(object):
    def isPalindrome(self, head):
        if head is None or head.next is None:
            return True
        mid = self.getMid(head)
        mid.next = self.getFanZhuan(mid.next)
        p,q = head,mid.next
        while q is not None and p.val == q.val:
            q = q.next
            p = p.next
        self.getFanZhuan(mid.next)
        return q == None
    def getMid(self,head):
        fast,slow = head.next,head
        while fast is not None and fast.next is not None:
            fast = fast.next.next
            slow = slow.next
        return slow
    def getFanZhuan(self,head):
        if head is None or head.next is None:
            return head
        pre,curr,next = None,head,head.next
        while curr is not None:
            curr.next = pre
            pre = curr
            curr = next
            next = None if next is None else next.next
        return pre
Copy the code
  1. Double linked list design Double linked list design is a little bit more complicated than a single linked list, but if you want to understand the sentry in a linked list, it’s pretty easy, but I did this problem for three days, and I do this problem every morning at 7:30. I think it took about 40 minutes, but I’m a little bit crazy, and when you’re designing data structures, you have to write multiple methods, and when you review code, you have to consider the effect of multiple functions calling each other, Class-level “invariants” require deep thinking about the role of each behavior, a careful understanding of the pre – and post-conditions under which each behavior occurs, and what is a constant state to be maintained throughout the life of an object.
class MyLinkedList(object):

    def __init__(self):
        """ Initialize your data structure here. """
        self.head = ListNode(- 1)
        self.tail = ListNode(- 1)
        self.head.next = self.tail
        self.tail.prev = self.head
        self.length = 0


    def get(self, index):
        """ Get the value of the index-th node in the linked list. If the index is invalid, return -1. :type index: int :rtype: int """
        if index < 0 or index >= self.length:
            return - 1
        return self.getNode(index).val


    def getNode(self,index):
        frist = self.head.next
        for i in range(index):
            frist = frist.next
        return frist                                                                                


    def addAtHead(self, val):
        """ Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list. :type val: int :rtype: void """
        frist = self.head.next
        node = ListNode(val)
        self.head.next = node
        node.prev = self.head
        node.next = frist
        frist.prev = node
        self.length += 1


    def addAtTail(self, val):
        """ Append a node of value val to the last element of the linked list. :type val: int :rtype: void """last = self.tail.prev node = ListNode(val) self.tail.prev = node node.next = self.tail last.next = node node.prev = last  self.length +=1


    def addAtIndex(self, index, val):
        """ Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted. :type index: int :type val: int :rtype: void """
        if index < 0 or index > self.length:
            return
        if index == self.length:
            self.addAtTail(val)
            returnold = self.getNode(index) node = ListNode(val) pre = old.prev pre.next = node node.prev = pre node.next = old old.prev =  node self.length +=1


    def deleteAtIndex(self, index):
        """ Delete the index-th node in the linked list, if the index is valid. :type index: int :rtype: void """
        if index < 0 or index >= self.length:
            return
        node = self.getNode(index)
        pre = node.prev
        next = node.next
        pre.next = next
        next.prev = pre
        node.next = None
        node.prev = None
        self.length -= 1

Copy the code
  1. Concatenating two ordered lists The key to this problem is the handling of exceptions where both input lists may be empty and may be of different lengths. They all need to be handled separately
class Solution(object):
    def mergeTwoLists(self, l1, l2):
        if l1 is None and l2 is None:
            return None
        elif l1 is None:
            return l2
        elif l2 is None:
            return l1
        sb ,headA,headB = ListNode(- 1),l1,l2
        headSB = sb
        while headA  and  headB :
            if headA.val > headB.val:
                sb.next = headB
                headB = headB.next
            elif headA.val < headB.val:
                sb.next = headA
                headA = headA.next
            else:
                sb.next = headA
                headA = headA.next
                sb = sb.next
                sb.next = headB
                headB = headB.next
            sb = sb.next
        if headA:
            sb.next = headA
        elif headB:
            sb.next = headB
        return headSB.next
Copy the code
  1. Adding two numbers represented in reverse lists this problem simplifies the code by using sentinels, while keeping an eye on the carry, which is very easy to do.
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        rem = 0
        dummy = ListNode(0)
        p = dummy
        while l1 or l2 or rem:
            s = (l1.val if l1 else 0)  + (l2.val if l2 else 0) + rem
            rem = s/10
            p.next = ListNode(s%10)
            p = p.next
            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next
        return dummy.next

Copy the code
  1. Flat multilevel bidirectional linked listsLet me explainhereIf there is no child list, it will continue to be traversed. The whole program is completed in a loop. The son list traversing the child table, head and tail of the list of Pointers, child list of the next end node pointer to subject list current next, if the next is not empty, it is prev Pointers point to the end node of the linked list, and then again to update the head of the linked list node, make its traverse the nodes of the current main chain table next pointer pointing to the list The prev pointer to the head of the child lists points to it in reverse, and the pointer to the children is assigned to None, and the current pointer points directly to next of the tail pointer of the merged child lists to reduce the number of traversals. Reciprocating iteration, specific can be understood according to the code, drawing. This topic is more complex in the pointer, drawing the analysis of assignment, is to writebug freeThe key.
class Solution(object):
        if not head:
            return None
        p = head
        while p:
            if not p.child:
                p = p.next
                continue

            p1 = p.child
            p2 = p.child
            while p2.next:
                p2 = p2.next

            p2.next = p.next
            if p.next:
                p.next.prev = p2
            p.next = p1
            p1.prev = p
            p.child = None
            p = p1

        return head

Copy the code
  1. Copying a linked list with a random pointer This topic is the key to understand the random pointer. When copying nodes, the replication of the random pointer is relative, so it must ensure that the node to which the random pointer points is relatively unchanged. Click here for details
class Solution(object):
    def copyRandomList(self, head):
        if not head:
            return None
        p = head
        while p:
            tmp = RandomListNode(p.label)
            tmp.next = p.next
            p.next = tmp
            p = tmp.next
        p = head
        while p:
            if p.random:
                p.next.random = p.random.next
            p = p.next.next
        n,o = head.next,head
        new = n
        while n:
            o.next = n.next
            o = o.next
            if not o:
                break
            n.next = o.next
            n = n.next
        return new
Copy the code
  1. The best way to solve this problem is to do it in linear time in constant space. First, reverse the whole sequence, and then reverse the two parts respectively when finding the partition point. Note that the tail pointer must be specified in reverse order, because lists are continuous

class Solution(object):
    def rotateRight(self, head, k):

        if head is None:
            return None
        if k == 0:
            return head
        count = 0
        end = None
        tmp = head
        while tmp:
            tmp = tmp.next
            count += 1
        head = self.nx(head,end)
        k = k % count
        tmp = head
        whilek ! =0:
            tmp = tmp.next
            k -= 1
            end = tmp
        new_head = self.nx(head,end)
        head.next = self.nx(end,None)
        return new_head


    def nx(self,head,end):
        if head is None:
            return None
        pre,curr,next = None,head,head.next
        whilecurr ! = end: curr.next = pre pre = curr curr = next next = next.nextif next else None
        return pre
Copy the code
  1. The nature of this problem is to investigate the relationship between linear structure and tree structure. How to use linear structure to store a binary search tree? An ordered linear list can be an array or a linked list. In this case, how to construct a binary search tree from an ordered linear list? Dichotomy is the key. Dichotomy is the mapping between ordered linear list and binary search. So how to pick the middle point of dichotomy? Array can calculate index index, linked list can use fast or slow pointer,ok now the problem is solved, look at the code.
class Solution(object):
    def sortedListToBST(self, head):
        return self.insterC(head,None)
    def insterC(self,head,tail):
        if head is tail:
            return None
        if head.next is tail:
            return TreeNode(head.val)
        fast = mid = head
        while fast is not tail and fast.next is not tail:
                mid = mid.next
                fast = fast.next.next
        tree = TreeNode(mid.val)
        tree.left = self.insterC(head,mid)
        tree.right = self.insterC(mid.next,tail)
        return tree

Copy the code
  1. Swap nodes in a linked list in pairsThis topic is similar to the idea of reverse order of linked list, but as long as we correctly understand the relationship of linked list Pointers, pay attention to the transformation of precursor, current node, and successor. Note the check code, the check of boundary conditions, the analysis of exceptions can be writtenbug freeIt’s all about patience and keeping your cool.details

class Solution(object):
    def swapPairs(self, head):
        if head is None:
            return head
        sb = ListNode(- 1)
        sb.next = head
        a = sb
        b = head
        c = head.next
        while c:
            a.next = c
            b.next = c.next
            c.next = b
            a = b
            b = b.next
            if b is None:
                break
            c = b.next
        return sb.next
Copy the code
  1. Sorting list This problem is essentially linked list implementation of merge sort, topic request O (nlong), linked list implementation merge sort of advantage is can be done under constant space merge, the disadvantage is that the query point can’t wanted to array in a constant time to complete, so their performance is slower than the array form some, but also in the same order of magnitude, and does not require space for storage, and additional Space, in some cases, is also a good choice. details
class Solution(object):
    def sortList(self, head):
        if head is None or head.next is None :
            return head

        mid =  self.getMid(head)
        left = self.sortList(head)
        right = self.sortList(mid)
        return self.merge(left,right)


    def getMid(self,head):
        m,k = head,head
        sb = ListNode(- 1)
        sb.next = head
        while k and k.next:
            k = k.next.next
            m = m.next
            sb = sb.next
        sb.next = None
        return m


    def merge(self,a,b):
        sb = ListNode(- 1)
        curr = sb
        while a and b:
            if a.val >= b.val:
                curr.next = b
                b = b.next
            else:
                curr.next = a
                a = a.next
            curr = curr.next
        if a:
            curr.next = a
        elif b:
            curr.next = b
        return sb.next
Copy the code
  1. Rearranging lists is a combination of three common linked list behaviors: fetching list midpoints, reversing linked lists, and cross-merging linked lists.
class Solution(object):
    def reorderList(self, head):
        if not head or not head.next:
            return
        if not head.next.next:
            return

        mid = self.get_mid(head)
        head1 =  self.nx(mid)
        head =  self.marge(head,head1)

    def get_mid(self,head):
        pre = ListNode(- 1)
        pre.next = head
        fast,slow = head,head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
            pre = pre.next
        pre.next = None
        return slow

    def nx(self,head):
        pre, cur, next = None,head,head.next
        while cur:
            cur.next = pre
            pre = cur
            cur = next
            if next:
                next = next.next
        return pre

    def marge(self,head1,head2):
        dummy = ListNode(- 1)
        d = dummy
        p, q = head1,head2
        while p and q:
            d.next = p
            p = p.next
            d = d.next

            d.next = q
            q = q.next
            d = d.next
        if q:
            d.next = q
        elif p:
            d.next = p
        return dummy.next

Copy the code
  1. The key of the linked list component understanding problem is to define the concept of components, which can be solved by using the characteristics of map key and determine the counting strategy. The key of this problem is to understand the new concept correctly, and identify the classic pattern – set search algorithm.
class Solution:
    def numComponents(self, head, G):
        if head is None or len(G) == 0:
            return 0
        count = 0
        cur = head
        GMap = {}
        for v in G:
            GMap[v] = 0
        while cur:
            if cur.val in GMap and (cur.next is None or cur.next.val not in GMap):
                count += 1                
            cur = cur.next
        return count

Copy the code
  1. Separated list 01 is solved in two steps. The first step is to find the partition rule. Second, divide according to rules. The rule is very simple according to the problem, it’s split first and then split the remainder and the problem is to find the rule, mathematically express it and encapsulate the behavior.
class Solution:
    def splitListToParts(self, root, k):
        p = root
        size = 1
        while p and p.next:
            size += 1
            p = p.next
        mod = size % k
        num = int(size / k)
        res = []

        tmp = root
        whilek ! =0:
            ifmod ! =0:
                root = self.splitListNodeByLen(tmp,num+1)
                mod -= 1
            else:
                root = self.splitListNodeByLen(tmp,num)
            res.append(tmp)
            tmp = root
            k -= 1
        return res


    def splitListNodeByLen(self,root,l):
        if not root or l <= 0:
            return root
        pre = None
        while l > 0:
            pre = root
            root = root.next
            l -= 1
        pre.next = None
        return root
Copy the code
  1. Two Numbers together II this topic is the upgrade version of the table together, even the table no longer reverse need to deal with, the collapse of the model is more general to the specific approach first, the solution to this problem I is bad, no best practice for reference, just I want to come out, since can’t from the beginning of the low, and operational problems, thought of using this auxiliary stack structure to handle directly. But it introduces additional complexity in the interim, and you can figure out how to optimize it later.
class Solution:
    def addTwoNumbers(self, l1, l2):
        s1, s2 = [], []
        tmp1 ,tmp2 = l1, l2
        while tmp1:
            s1.append(tmp1.val)
            tmp1 = tmp1.next
        while tmp2:
            s2.append(tmp2.val)
            tmp2 = tmp2.next
        c = 0
        node = ListNode(- 1)
        root = node
        whilelen(s1) ! =0 andlen(s2) ! =0:
            num = s1[- 1] + s2[- 1] + c
            s1 = s1[:len(s1)- 1]
            s2 = s2[:len(s2)- 1]
            if num >= 10:
                node.val = num - 10
                c = 1
            else:
                node.val = num
                c = 0
            if len(s1) == 0 and len(s2) == 0:
                if c == 1:
                    node.next = ListNode(- 1)
                    node = node.next
                    node.val =  c
                break
            node.next = ListNode(- 1)
            node = node.next

        whilelen(s1) ! =0:
            num = s1[- 1] + c
            if num >= 10:
                node.val = num - 10
                c = 1
            else:
                node.val = num
                c = 0
            s1 = s1[:len(s1)- 1]
            if len(s1) == 0:
                if c == 1:
                    node.next = ListNode(- 1)
                    node = node.next
                    node.val = c
                break
            node.next = ListNode(- 1)
            node = node.next

        whilelen(s2) ! =0:
            num = s2[- 1] + c
            if num >= 10:
                node.val = num - 10
                c = 1
            else:
                node.val = num
                c = 0
            s2 = s2[:len(s2)- 1]
            if len(s2) == 0:
                if c == 1:
                    node.next = ListNode(- 1)
                    node = node.next
                    node.val = c
                break
            node.next = ListNode(- 1)
            node = node.next
        return self.nx(root)

    def nx(self,root):
        if root is None:
            return None
        pre = None
        next = root.next
        while root:
            root.next = pre
            pre = root
            root = next
            if next:
                next = next.next
        return pre
Copy the code
  1. This problem is the implementation of a linked list in a quicksort partition.
class Solution:
    def partition(self, head, x):
        h1,h2 = ListNode(- 1),ListNode(- 1)
        dummy = ListNode(- 1)
        dummy.next = head
        pre = dummy
        tmp1,tmp2 = h1,h2
        while pre and pre.next:
            tmp = pre.next
            pre.next = None
            pre = tmp
            if tmp.val >= x:
                tmp1.next = tmp
                tmp1 = tmp1.next
            else:
                tmp2.next = tmp
                tmp2 = tmp2.next
        tmp2.next = h1.next
        return h2.next
Copy the code
  1. Reverse linked list II this problem pointer more drawing aid more efficient.
class Solution:
    def reverseBetween(self, head, m, n):
        count = 0
        dummy = ListNode(- 1)
        pre = dummy
        pre.next = head
        while count < m- 1:
            pre = pre.next
            count += 1
        last = pre
        while count < n:
            last = last.next
            count += 1
        cur = pre.next
        next = last.next
        self.reverse(cur, last)
        pre.next = last
        head = dummy.next
        cur.next = next
        return head
    def reverse(self, cur,last):
        last.next = None;
        pre = None
        next = cur.next
        while cur:
            cur.next = pre
            pre = cur
            cur = next
            if next:
                next = next.next
Copy the code
  1. Add the two numbers using the sentinel pattern
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        "" "" ""
        rem = 0
        dummy = ListNode(0)
        p = dummy
        while l1 or l2 or rem:
            s = (l1.val if l1 else 0)  + (l2.val if l2 else 0) + rem
            rem = s/10
            p.next = ListNode(s%10)
            p = p.next
            if l1:
                l1 = l1.next
            if l2:
                l2 = l2.next
        return dummy.next
Copy the code
  1. Plus One Linked List(1) leetCode If no such number is found, all numbers are 9. Create a new node with a value of 0 at the top of the table, increment by 1, and set all numbers on the right to 0. For example:

For example, 1->2->3, then the first digit that is not 9 is 3, add 1 to 3, become 4, there is no node on the right side, so do not do processing, return 1->2->4.

For example, 8->9->9, find the first digit that is not 9 is 8, add 1 to become 9, and then set the following digits to 0, get 9->0->0.

If 9->9->9 is not found, create a new node with a value of 0 in front, add 1 to become 1, set all the following digits to 0, get 1->0->0->0 ->0.

class Solution {
public:
    ListNode* plusOne(ListNode* head) {
        ListNode *cur = head, *right = NULL;
        while (cur) {
            if(cur->val ! =9) right = cur;
            cur = cur->next;
        }
        if(! right) { right =new ListNode(0);
            right->next = head;
            head = right;
        }
        ++right->val;
        cur = right->next;
        while (cur) {
            cur->val = 0;
            cur = cur->next;
        }
        returnhead; }};Copy the code
  1. Design Phone Directory Here, speak clearly, need not I said again, the design of the main investigation data structure, in fact, this kind of question first according to the experience to the most common structure can meet the requirements, the deficiencies are trying combination data structure, the key is to define what information do you want to know to make you one step closer to the right answer, it takes practice and summary.

  2. Remove the key from a Binary Search Tree to Sorted Doubly-linked List. A very classic problem,LeetCode charges, there is no way to OJ, the local only go environment. So I wrote a solution in terms of go.

This problem uses divide and conquer idea, recursive realization. The pattern of the original problem can be seen as: left subtree loop merging with root loop merging with right subtree loop merging. Thus, the subproblem is: 1. “left subtree root right subtree” ring,2. A merger. The recursion base is obviously null and returns directly. The recursive part is: left, right ring. Each recursion does just that: join the root into a loop, and merge the left root and right rings. The merge action is a function of joining two circular lists into a linked list.

type TreeNode struct {
	Left  *TreeNode
	Right *TreeNode
	Val   int
}
func BST2DLL(root *TreeNode) *TreeNode {
	if root == nil{
		return nil} aLast := BST2DLL(root.Left) bLast := BST2DLL(root.Right) root.Left = root root.Right = root aLast = Append(aLast,root)  aLast = Append(aLast,bLast)return aLast
}
func Append(a,b *TreeNode) *TreeNode  {
	if a == nil{
		return b
	}
	if b == nil{
		return a
	}
	 aLast := a.Left
	 bLast := b.Left
	 Join(aLast, b)
	 Join(bLast, a)
	return a
}
func Join(a, b *TreeNode) {
	a.Right = b
	b.Left = a
}

Copy the code

30. The problem of Insert into a Cyclic Sorted List to Insert nodes into a Cyclic Sorted List is an analysis of various situations. The first problem is that when the List is empty, the Insert value is between the maximum and minimum, less than the minimum or greater than the maximum. Consider the different situations. I’m going to follow the number line. 31. A set of k flip linked lists uses the sentry to reduce pointer operations, and uses K as a counter to control the pre,left, and right boundary Pointers for operation. Flip the linked list by moving the pointer to the correct position according to the counter. The method is clumsy but simple and effective haha, I will optimize it later. Now I will try my best to practice the basic model by seeing more types and collecting more data.

class Solution:
    def reverseKGroup(self, head, k):
        """ :type head: ListNode :type k: int :rtype: ListNode """
        if k <= 0 or not head or not head.next:
            return head
        dummy = ListNode(- 1)
        dummy.next = head
        cur = head
        pre = dummy
        while cur:
            left,right = cur,cur
            for i in range(k- 1):
                cur = cur.next
                if cur is None:
                    return dummy.next
                right = cur
            self.nx(pre,left,right)
            cur = left
            pre = left
            cur = cur.next
        return dummy.next
    def nx(self,pre,l,r):
        if not pre or not l or not r or l == r:
            return l
        p ,cur,next = pre,l,l.next
        tmp = r.next
        whilecur ! = tmp: cur.next = p p = cur cur = nextif next:
                next = next.next
        pre.next = p
        l.next = tmp
Copy the code

32. Merge K sorted lists this problem can be done very nicely, but I will give you an intuitive brute force solution, which will be improved in the future. This problem can be understood as: select the largest node from the list each time, remove it from the list and use sentinels to form new nodes, then update the linked list, continuously drop generations, and finally end when the list is empty.

class Solution:
    def mergeKLists(self, lists):
        """ :type lists: List[ListNode] :rtype: ListNode """
        dummy = ListNode(- 1)
        cur = dummy
        whilelen(lists) ! =0:
            index = self.min(lists)
            if not lists[index]:
                del lists[index]
                continue
            cur.next = lists[index]
            if lists[index] and lists[index].next:
                lists[index] = lists[index].next
            else:
                del lists[index]
            cur = cur.next
        return dummy.next
    def min(self,lists):
        m = lists[0]
        index = 0
        i = 1
        while i<len(lists):
            if lists[i] and m and m.val > lists[i].val:
                m = lists[i]
                index = i
            i += 1
        return index
Copy the code

33. The idea of deleting a node from a linked list is clever. You only have a given node and no pointer to a precursor node. Ingenious use of the idea of assignment to solve.

class Solution:
    def deleteNode(self, node):
        """ :type node: ListNode :rtype: void Do not return anything, modify node in-place instead. """
        tmp = node.next
        node.next = node.next.next
        tmp.next = None
        node.val = tmp.val
Copy the code

34. The middle node of the linked list was originally placed in the first order, but it was found that it was not written, so I added it here. As mentioned many times before, intermediate nodes, fast or slow Pointers

class Solution(object):
    def middleNode(self, head):
        """ :type head: ListNode :rtype: ListNode """
        if not head and not head.next:
            return head
        slow,fast = head,head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
        return slow
Copy the code