Chain Table of Leetcode Brush Titles

Posted by Gath on Sun, 26 Sep 2021 19:13:25 +0200

Chain Table Paper

24.Nodes in a two-way exchange chain table

  • Idea 1: Introduce sentinel node, adopt double pointer pre, cur
class Solution(object):
    def swapPairs(self, head):
        auxi = ListNode(0,next = head)
        pre,cur = auxi,head
        while cur and cur.next:
            tmp = cur.next
            cur.next = tmp.next 
            tmp.next = cur
            pre.next = tmp
            pre = cur
            cur = cur.next
        return auxi.next

Summary: Sentry nodes can be introduced when the head node is uncertain

141.Circular linked List

  • Idea 1: Fast and slow pointers, if looped, must intersect
  • Idea 2: Record visited nodes with a collection, and loop if present
#Idea 1: Fast and slow pointers
class Solution(object):
    def hasCycle(self, head):
        if not head: return head
        fast,slow = head,head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow==fast: return True
        return False
#Idea 2: Collection
class Solution(object):
    def hasCycle(self, head):
        myset = set()
        while head:
            if head not in myset:
                myset.add(head)
            else: return True
            head = head.next
        return False

Summary: Chain lists are looped with fast and slow pointers

142.Ring Chain Table II

  • Idea 1: Fast and slow pointers. If they are looped, the head node and the fast and slow pointer intersect each other next. The final intersection is the ring intersect node
  • Idea 2: Record visited nodes with a collection, and if looped, the first node that repeats is the intersecting node
#Idea 1: Fast and slow pointers
class Solution(object):
    def detectCycle(self, head):
        if not head or not head.next: return None
        pre,cur = head,head
        while cur and cur.next:
            pre = pre.next
            cur = cur.next.next
            if pre == cur: # Represents Ring
                p1 = head
                p2 = cur
                while p1!=p2:
                    p1 = p1.next
                    p2 = p2.next
                return p1
        return None
#Idea 2: Collection
class Solution(object):
    def detectCycle(self, head):
        mySet = set()
        while(head):
            if head not in mySet:
                mySet.add(head)
            else:
                return head
            head = head.next
        return None

Summary: Chain lists are looped with fast and slow pointers

86.Separated Chain List

  • Idea 1: For the question of separating the elements of a chain table, consider introducing multiple sentinel nodes, joining different sub-chain lists, and then stitching them together
  • Idea 2: Separate the linked list nodes with two extra arrays, then stitch the arrays, and join the nodes of the arrays back and forth
# Idea 1: Sentinel Node
class Solution(object):
    def partition(self, head, x):
        if not head: return None
        auxi1,auxi2 = ListNode(0),ListNode(0)
        cur1,cur2 = auxi1,auxi2
        while head:
            if head.val < x:
                cur1.next = head
                cur1 = cur1.next
            else:
                cur2.next = head
                cur2 = cur2.next
            head = head.next
        cur1.next = auxi2.next
        cur2.next = None
        return auxi1.next
# With arrays
class Solution(object):
    def partition(self, head, x):
        if not head: return None
        nums1,nums2 = [],[]
        while head:
            if head.val < x:
                nums1.append(head)
            else:
                nums2.append(head)
            head = head.next
        nums1.extend(nums2)
        for i in range(len(nums1)-1):
            nums1[i].next = nums1[i+1]
        nums1[-1].next = None
        return nums1[0]

Summary: Multiple Sentinel Nodes are introduced to separate, and the last element of the chain table points to None

328.Parity Chain List

  • Idea 1: For the question of separating the elements of a chain table, consider introducing multiple sentinel nodes, joining different sub-chain lists, and then stitching them together
  • Idea 2: Separate the linked list nodes with two extra arrays, then stitch the arrays, and join the nodes of the arrays back and forth
# Idea 1: Sentinel Node
class Solution(object):
    def oddEvenList(self, head):
        auxi1,auxi2 = ListNode(0),ListNode(0)
        cur1,cur2 = auxi1,auxi2
        cnt = 0
        while head:
            cnt += 1
            if cnt % 2!= 0 :
                cur1.next = head
                cur1 = cur1.next
            else:
                cur2.next = head
                cur2 = cur2.next
            head = head.next
        cur1.next = auxi2.next
        cur2.next = None
        return auxi1.next
# With arrays
class Solution(object):
    def oddEvenList(self, head):
        if not head: return None
        nums1,nums2 = [],[]
        cnt = 1
        while head:
            if cnt%2==1:
                nums1.append(head)
            else:
                nums2.append(head)
            cnt += 1
            head = head.next
        nums1.extend(nums2)
        for i in range(len(nums1)-1):
            nums1[i].next = nums1[i+1]
        nums1[-1].next = None
        return nums1[0]

Summary: Multiple Sentinel Nodes are introduced to separate, and the last element of the chain table points to None

19.Delete the last N th node in the list of chains

  • Idea 1: Fast slow pointer, slow pointer walk n steps later than fast pointer
class Solution(object):
    def removeNthFromEnd(self, head, n):
        tmp = ListNode(0)
        tmp.next = head
        pre,cur = tmp,head
        cnt = 0
        while head:
            cnt += 1
            if cnt > n: # Slow pointer walk n steps late
                pre = cur
                cur = cur.next
            head = head.next
        pre.next = cur.next # Fast and slow pointers delete the last nth node
        return tmp.next

22.The last k th node in the list of chains

  • Idea 1: Fast slow pointer, slow pointer walk k steps later than fast pointer
class Solution(object):
    def getKthFromEnd(self, head, k):
        pre,cur = head,head
        cnt = 0
        while cur:
            cnt += 1
            if cnt>k:
                pre = pre.next
            cur = cur.next
        return pre

61.Rotating Chain List

  • Idea 1: First traverse to the end of the list and record the length L of the list, the end node points to the head node to form a ring, then points to the head node pointer cur to move L-k times, break the loop, cur is the new head node
class Solution(object):
    def rotateRight(self, head, k):
        if not head: return head
        cnt,cur,pre = 0,head,head
        while cur:
            cnt += 1
            pre = cur
            cur = cur.next
        pre.next = head # Ring
        pre,cur = head,head
        k = cnt - k % cnt
        while cur:
            k -= 1
            pre = cur
            cur = cur.next
            if k == 0:
                pre.next = None
                break
        return cur

Summary: The last element of the list points to None

138.Copy a chain table with random pointers

  • Idea 1: Copy one node after each node of the original chain table, and then separate according to parity to get a new copy list
  • Idea 2: Introduce a dictionary, iterate through the list of chains, record old nodes and new nodes one-to-one. The random pointer of the new node points to the position, which can be obtained by looking up the dictionary according to the pointing position of the old node corresponding to the new node.
# Idea One
class Solution(object):
    def copyRandomList(self, head):
        if not head: return None
        cur = head
        while cur:
            tmp = cur.next
            cur.next = Node(cur.val,next=tmp,random=cur.random)
            cur = tmp
        cur = head
        while cur:
            tmp = cur.next.next
            if cur.random:
                cur.next.random = cur.random.next
            else:
                cur.next.random = None
            cur = tmp
        ret,pre,cur = head.next,head,head.next
        while cur and cur.next:
            tmp1 = pre.next.next
            tmp2 = tmp1.next
            pre.next = tmp1
            cur.next = tmp2
            cur = tmp2
            pre = tmp1
        cur.next = None
        pre.next = None
        return ret

# Idea Two
class Solution(object):
    def copyRandomList(self, head):
        auxi = Node(0)
        pre,mydict = auxi,{}
        while head:
            tmp = Node(head.val)
            pre.next = tmp
            pre = tmp
            mydict[head] = tmp
            head = head.next
        for k,v in mydict.items():
            if k.random: v.random = mydict[k.random] # k.random is not None before a dictionary is saved
            else: v.random = None
        return auxi.next

Summary: Copying a list of chains allows you to copy a copy between each node of the original list, then separate it; there is a one-to-one correspondence that can be introduced into a dictionary.

146.LRU Cache Mechanism

  • Idea 1: Using the form of two-way Chain Table + dictionary, dictionary for fast lookup, two-way chain table for updating the most recently visited data nodes to head, the most recently visited nodes are found and deleted by tail
# Core Idea: Two-way Chain List + Dictionary
class DlinkNode(object):
    def __init__(self,key=0,val=0):
        self.key = key
        self.val = val
        self.pre = None
        self.next = None

class LRUCache(object):
    def __init__(self, capacity):
        self.head = DlinkNode()
        self.tail = DlinkNode()
        self.head.next = self.tail
        self.tail.pre = self.head
        self.capacity = capacity
        self.size = 0
        self.cache = {}

    def get(self, key):
        if key not in self.cache:
            return -1
        else:
            node = self.cache[key]
            self.moveToHead(node)
            return node.val

    def put(self, key, value):
        if key in self.cache:
            self.cache[key].val = value
            self.moveToHead(self.cache[key])
        else:
            node = DlinkNode(key,value)
            if self.size == self.capacity:
                tail = self.removeTail()
                self.cache.pop(tail.key)
                self.size -= 1
            self.cache[key] = node
            self.addToHead(node)
            self.size += 1
    
    def removeNode(self,node):
        node.pre.next = node.next
        node.next.pre = node.pre

    def addToHead(self,node):
        self.head.next.pre = node
        node.next = self.head.next
        node.pre = self.head
        self.head.next = node

    def moveToHead(self,node):
        self.removeNode(node)
        self.addToHead(node)
    
    def removeTail(self):
        node = self.tail.pre
        self.removeNode(node)
        return node

Summary: LRU cache uses the idea of two-way Chain Table + dictionary

Topics: data structure leetcode linked list