def removeNthFromEnd(self, head: 'ListNode', n: 'int') -> 'ListNode': refDict = {} cnt = 0 fakeHead = ListNode(None) fakeHead.next = head while fakeHead is not None: cnt += 1 refDict[cnt] = fakeHead fakeHead = fakeHead.next # When list is too short, return the original list head directly. if cnt > n: # The node to be deleted is stored at refDict[cnt - n + 1]. refDict[cnt - n].next = refDict.get(cnt - n + 2) return refDict[1].next
def partition(self, head: ListNode, x: int) -> ListNode: lHead = l = ListNode(0) rHead = r = ListNode(0) currNode = head while currNode: if currNode.val < x: l.next = currNode l = l.next else: r.next = currNode r = r.next currNode = currNode.next # Note that the current r should be the last node in the new list. r.next = None l.next = rHead.next return lHead.next
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: """ Cheat answer: python does not have a limit on integer. """ def get_number(l: ListNode) -> int: rslt, curr = 0, l while curr: rslt = rslt * 10 + curr.val curr = curr.next return rslt n = str(get_number(l1) + get_number(l2)) dummyHead = currNode = ListNode(None) for c in n: currNode.next = ListNode(int(c)) currNode = currNode.next return dummyHead.next
def removeElements(self, head: ListNode, val: int) -> ListNode: newHead = preHead = ListNode(None) newHead.next = currHead = head while currHead: if currHead.val == val: preHead.next = currHead.next else: preHead = preHead.next currHead = currHead.next return newHead.next
def swapPairs(self, head: 'ListNode') -> 'ListNode': fakeHead = ListNode(None) pre = fakeHead pre.next = head while pre.next and pre.next.next: n1 = pre.next n2 = n1.next pre.next, n1.next, n2.next = n2, n2.next, n1 pre = n1 return fakeHead.next
def reverseKGroup(self, head: ListNode, k: int) -> ListNode: fakeHead = ListNode(None) fakeHead.next = l = r = head jump, cnt = fakeHead, 0 while True: cnt = 0 while r and cnt < k: # Advance r until it points to Node(k+1). cnt += 1 r = r.next if cnt == k: # List is long enough to hold a k group. pre, curr = r, l for _ in range(k): # Swap k times to reverse the k group. """ It reverses each node by cutting it from the k group, then pre-append it with the rest of the list after the k group. Each loop cuts one node starting from the last node in the k group to the first node. For example: Initiallly: k = 3 pre = 4 -> None curr = 1 -> 2 -> 3 -> 4 -> None Round 0: pre = 1 -> 4 -> None curr = 2 -> 3 -> 4 -> None Round 1: pre = 2 -> 1 -> 4 -> None curr = 3 -> 4 -> None Round 2: pre = 3 -> 2 -> 1 -> 4 -> None curr = 4 -> None Now the nodes in the k group is reversed and stored in pre. """ temp = curr.next # Store curr.next for later reference. curr.next = pre # Pre-append current node to the remain. pre = curr # Move remain pointer to the current node. curr = temp # Move current node to the previous next node. jump.next = pre # Append the reversed node list to fakeHead. jump = l # Move jump to the end point of the current k group. l = r # Set l to the first item in the next k group. else: # List is exhausted. return fakeHead.next
def deleteDuplicates(self, head: ListNode) -> ListNode: rslt = preNode = ListNode(0) preNode.next = currNode = head while currNode and currNode.next: if currNode.val == currNode.next.val: currNode = currNode.next while currNode and currNode.next and \ currNode.val == currNode.next.val: currNode = currNode.next preNode.next = currNode = currNode.next else: preNode = preNode.next currNode = currNode.next return rslt.next
def mergeTwoLists(self, l1: 'ListNode', l2: 'ListNode') -> 'ListNode': dumyHead = ListNode(None) temp = dumyHead while l1 and l2: if l1.val > l2.val: temp.next = l2 l2 = l2.next else: temp.next = l1 l1 = l1.next temp = temp.next if l1: temp.next = l1 if l2: temp.next = l2 return dumyHead.next
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode: # Presumption: 1 <= m <= n <= length of the list. rslt = preNode = ListNode(0) preNode.next = currNode = head cnt = 1 while cnt < m: # Move to the Node m. preNode, currNode = preNode.next, currNode.next cnt += 1 tailNode, nextNode = currNode, currNode.next tailNode.next = None while cnt < n: # Move to the Node n. tempNode = nextNode.next nextNode.next = currNode currNode = nextNode nextNode = tempNode cnt += 1 tailNode.next = nextNode preNode.next = currNode return rslt.next
""" https://leetcode.com/problems/remove-duplicates-from-sorted-list-ii/ """ from test_helper import ListNode class Solution: def deleteDuplicates(self, head: ListNode) -> ListNode: rslt = preNode = ListNode(0) preNode.next = currNode = head while currNode and currNode.next: if currNode.val == currNode.next.val: currNode = currNode.next while currNode and currNode.next and \ currNode.val == currNode.next.val: currNode = currNode.next preNode.next = currNode = currNode.next else: preNode = preNode.next currNode = currNode.next return rslt.next a = ListNode(0).create_node_list(givenList=[1, 1]) print(Solution().deleteDuplicates(a))
def removeNthFromEnd(self, head: 'ListNode', n: 'int') -> 'ListNode': refDict = {} cnt = 0 fakeHead = ListNode(None) fakeHead.next = head while fakeHead is not None: cnt += 1 refDict[cnt] = fakeHead fakeHead = fakeHead.next # When list is too short, return the original list head directly. if cnt > n: # The node to be deleted is stored at refDict[cnt - n + 1]. refDict[cnt - n].next = refDict.get(cnt - n + 2) return refDict[1].next x = ListNode(None).create_node_list(1, 2) print('Original List:') x.print_node_list() offset = 1 print('Removing {0}th node from the end of the list...'.format(offset)) print('Updated List:') y = Solution().removeNthFromEnd(x, offset) if y is not None: y.print_node_list() else: print(y)
""" https://leetcode.com/problems/swapping-nodes-in-a-linked-list/ """ from test_helper import ListNode class Solution: def swapNodes(self, head: ListNode, k: int) -> ListNode: currNode, rKthNode = head, None cnt = 0 kthNode = None while currNode: if rKthNode: rKthNode = rKthNode.next cnt += 1 if cnt == k: rKthNode = head kthNode = currNode currNode = currNode.next kthNode.val, rKthNode.val = rKthNode.val, kthNode.val return head head = ListNode(1) print(Solution().swapNodes(head, 1))
""" https://leetcode.com/problems/remove-duplicates-from-sorted-list/ """ from test_helper import ListNode class Solution: def deleteDuplicates(self, head: ListNode) -> ListNode: currNode = head while currNode and currNode.next: if currNode.val == currNode.next.val: currNode.next = currNode.next.next else: currNode = currNode.next return head head = ListNode(0).create_node_list(givenList=[1, 1, 2]) print(Solution().deleteDuplicates(head))
# Find the middle node of the list first. middleNode, tailNode = head, head.next while tailNode and tailNode.next: middleNode = middleNode.next tailNode = tailNode.next.next currNode, nextNode = middleNode.next, middleNode.next.next # Cut the list at the middle point. middleNode.next, currNode.next = None, None # Reverse the half list starting at the currNode. while nextNode: tempNode = nextNode.next nextNode.next = currNode currNode = nextNode nextNode = tempNode # Merge the two lists. currNode, nextNode = head, currNode while currNode: tempNode = currNode.next currNode.next = nextNode currNode = nextNode nextNode = tempNode root = ListNode(None).create_node_list(1, 5) Solution().reorderList(root) print(root.print_single_list())
from test_helper import ListNode class Solution: def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]: if not root: return [None] * k # First calculate the total length of the list. currNode, total = root, 0 while currNode: total += 1 currNode = currNode.next partLen, remainLen = divmod(total, k) currNode, rslt, partCnt = root, [], 0 for partCnt in range(k): # Split list to parts with partLen length. rslt.append(currNode) for _ in range(partLen + (partCnt < remainLen)): preNode, currNode = currNode, currNode.next preNode.next = None return rslt root = ListNode(1) root.create_node_list(1, 11) print(Solution().splitListToParts(root.next, 3))
""" https://leetcode.com/problems/linked-list-components/ """ from test_helper import ListNode class Solution: def numComponents(self, head: ListNode, G: list[int]) -> int: cnt = 0 nodes = set(G) currNode = head while currNode and nodes: nextNode = currNode.next if nextNode: if currNode.val in nodes and nextNode.val not in nodes: cnt += 1 elif currNode.val in nodes: cnt += 1 currNode = nextNode return cnt head = ListNode(None).create_node_list(0, 4) print(Solution().numComponents(head, [0, 1, 3]))
def deleteNode(self, node: ListNode): node.val = node.next.val node.next = node.next.next
""" Use bottom-up merge sort to achieve the o(nlogn) runtime and the o(1) space. """ if not head or not head.next: # Empty or only one node. return head # Get the total size of the list first. n, currNode = 0, head while currNode: n, currNode = n + 1, currNode.next # Keep cutting and merging the sub lists. step, dummyHead = 1, ListNode(None) dummyHead.next = head while step < n: currHead, currTail = dummyHead.next, dummyHead while currHead: leftHead = currHead rightHead = self._cut_list(leftHead, step) currHead = self._cut_list(rightHead, step) currTail = self._merge_list(leftHead, rightHead, currTail) step *= 2 return dummyHead.next head = ListNode(None).create_node_list(givenList=[6, 5, 4, 3, 2, 1]) print(Solution().sortList(head).print_single_list())
4. So now the slow has to be moved s1 steps in order to get to the start point of the cycle, while the fast is now at k + 1 + s1 - r = r + s1 - r = s1, which is also the start point of the cycle. So now we have finally found the start point of the cycle. """ if not head or not head.next: return None # Try to find the meet point when the fast just runs one more cycle. # than the slow. slow, fast = head, head.next while slow != fast: if not fast or not fast.next: # The fast reaches the end. return None slow = slow.next fast = fast.next.next slow, fast = head, fast.next while slow != fast: slow = slow.next fast = fast.next # Now both the slow and fast points to the cycle start point. return slow print(Solution().detectCycle( ListNode(None).create_cycle_list([3, 2, 0, -4], 1)))
from test_helper import ListNode class Solution: def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode: # Presumption: 1 <= m <= n <= length of the list. rslt = preNode = ListNode(0) preNode.next = currNode = head cnt = 1 while cnt < m: # Move to the Node m. preNode, currNode = preNode.next, currNode.next cnt += 1 tailNode, nextNode = currNode, currNode.next tailNode.next = None while cnt < n: # Move to the Node n. tempNode = nextNode.next nextNode.next = currNode currNode = nextNode nextNode = tempNode cnt += 1 tailNode.next = nextNode preNode.next = currNode return rslt.next print(Solution().reverseBetween(ListNode(0).create_node_list( givenList=[1]), 1, 1))
""" https://leetcode.com/problems/swap-nodes-in-pairs/ """ from test_helper import ListNode class Solution: def swapPairs(self, head: 'ListNode') -> 'ListNode': fakeHead = ListNode(None) pre = fakeHead pre.next = head while pre.next and pre.next.next: n1 = pre.next n2 = n1.next pre.next, n1.next, n2.next = n2, n2.next, n1 pre = n1 return fakeHead.next l = ListNode(None).create_node_list(givenList=[1, 2, 3, 4]) print('The original list is:') print(l) print('The swapped list is:') print(Solution().swapPairs(l))
class Solution: def insertionSortList(self, head: ListNode) -> ListNode: dummyHead = ListNode(None) currNode, dummyHead.next, preInsertPos = head, head, dummyHead while currNode and currNode.next: # The current node always points to the end of the sorted sequece. nextVal = currNode.next.val if nextVal < currNode.val: # The next node needs to be inserted to the current sequence. # Try to find the insert position first. if nextVal < preInsertPos.next.val: preInsertPos = dummyHead while preInsertPos.next and preInsertPos.next.val <= nextVal: preInsertPos = preInsertPos.next # Insert the nextNode between preInsertPos # and preInsertPos.next. newNode = currNode.next currNode.next = newNode.next newNode.next = preInsertPos.next preInsertPos.next = newNode else: currNode = currNode.next # Sort the next node. return dummyHead.next head = ListNode(None).create_node_list(givenList=[4, 2, 1, 3]) print(Solution().insertionSortList(head).print_single_list())
Initiallly: k = 3 pre = 4 -> None curr = 1 -> 2 -> 3 -> 4 -> None Round 0: pre = 1 -> 4 -> None curr = 2 -> 3 -> 4 -> None Round 1: pre = 2 -> 1 -> 4 -> None curr = 3 -> 4 -> None Round 2: pre = 3 -> 2 -> 1 -> 4 -> None curr = 4 -> None Now the nodes in the k group is reversed and stored in pre. """ temp = curr.next # Store curr.next for later reference. curr.next = pre # Pre-append current node to the remain. pre = curr # Move remain pointer to the current node. curr = temp # Move current node to the previous next node. jump.next = pre # Append the reversed node list to fakeHead. jump = l # Move jump to the end point of the current k group. l = r # Set l to the first item in the next k group. else: # List is exhausted. return fakeHead.next x = ListNode(None) print(Solution().reverseKGroup(x.create_node_list(1, 5), 3))
tempNode.next = l1 l1 = l1.next else: tempNode.next = l2 l2 = l2.next tempNode = tempNode.next if l1: tempNode.next = l1 if l2: tempNode.next = l2 lists[i] = fakeHead.next # Store merged list back to lists[i]. interval *= 2 # Increase interval. return lists[0] x = ListNode(None) s = Solution() l1 = x.create_node_list(givenList=[1, 4, 5]) l2 = x.create_node_list(givenList=[1, 3, 4]) l3 = x.create_node_list(givenList=[2, 6]) print('Original list is: ') for l in [l1, l2, l3]: l.print_node_list() print('Merged list is:') s.mergeKLists([l1, l2, l3]).print_node_list()
""" https://leetcode.com/problems/partition-list/ """ from test_helper import ListNode class Solution: def partition(self, head: ListNode, x: int) -> ListNode: lHead = l = ListNode(0) rHead = r = ListNode(0) currNode = head while currNode: if currNode.val < x: l.next = currNode l = l.next else: r.next = currNode r = r.next currNode = currNode.next # Note that the current r should be the last node in the new list. r.next = None l.next = rHead.next return lHead.next head = ListNode(0).create_node_list(givenList=[1, 4, 3, 2, 5, 2]) print(Solution().partition(head, 3))