def reorderList(self, head: ListNode) -> None: """Do not return anything, modify head in-place instead. """ s = ListNode('') s.next = head # step 1: reverse the 2nd half of the linked list: 1->2->3->4->5 to 1->2->3<-4<-5 x = y = s while y: x = x.next y = y.next if y: y = y.next # x is the middle one, reverse from x to ende prev, curr = None, x while curr: hold = curr.next curr.next = prev prev = curr curr = hold # step 2: two pointers from init and ende to switch 1(x)->2->3<-4<-5(y) to 1->5->2(x)->3<-4(y) to 1->5->2->4->3 x, y = head, prev while not (x == y or x.next == y): # hold of x.next and y.next u, v = x.next, y.next x.next = y y.next = u x, y = u, v return None
def deleteNode(self, node: ListNode) -> None: """Do not return anything, modify node in-place instead. Key: O(1), move the value of node.next, and link from node to node.next.next. The key is since we don't have prev, we modify this node as prev and instead delete node.next as node. """ node.val = node.next.val node.next = node.next.next
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode: if m == n: return head s = ListNode('') s.next = head i = 0 x = y = z = s while i < m - 1: x = x.next y = y.next z = z.next i += 1 y = y.next z = z.next i += 1 p = x while i < n: q = z.next z.next = p p = z z = q i += 1 x.next = z y.next = z.next z.next = p return s.next
def rotateRight(self, head: ListNode, k: int) -> ListNode: """Two pointers. """ s = ListNode(0) s.next = head if not s.next: return s.next x, y, i = s, s, 0 while i < k: if y.next: y = y.next else: y = s.next k %= i if k == 0: k += i * 2 else: k += i i += 1 while y.next: x = x.next y = y.next if not x == s: y.next = s.next s.next = x.next x.next = None return s.next
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: """Q0002 """ # parse list to str x1 = self._parse(l1) x2 = self._parse(l2) # add over strs n1 = len(x1) n2 = len(x2) # zip truncation if n1 < n2: x1 = "0" * (n2 - n1) + x1 else: x2 = "0" * (n1 - n2) + x2 # add over strs s = ListNode('') k, node = 0, s for i1, i2 in zip(x1[::-1], x2[::-1]): v = k + int(i1) + int(i2) k = v // 10 v %= 10 node.prev = ListNode(v) node.prev.next = node node = node.prev if k: node.prev = ListNode(k) node.prev.next = node node = node.prev # sentinel if node == s: node = None else: s.prev.next = None return node
def removeZeroSumSublists(self, head: ListNode) -> ListNode: # linked list -> array node, nums = head, [] while node: nums.append(node.val) node = node.next # consecutive sum 0 <=> prefix sum seen prefix, seen, remove = list(accumulate(nums)), {}, set() for i, x in enumerate(prefix): if x == 0: for k in range(i + 1): remove.add(k) elif x in seen and seen[x] not in remove: for k in range(seen[x] + 1, i + 1): remove.add(k) else: seen[x] = i ans = [nums[i] for i in range(len(nums)) if i not in remove] # array -> linked list s = prev = ListNode('') for x in ans: curr = ListNode(x) prev.next = curr prev = curr return s.next
def deleteNode(self, node: ListNode) -> None: """Do not return anything, modify node in-place instead. Key: O(N), move the value one by one while traverse from node to tail. """ while node.next.next: node.val = node.next.val node = node.next node.val = node.next.val node.next = None
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: s = l = ListNode(0) while l1 and l2: if l1.val <= l2.val: l.next = ListNode(l1.val) l1 = l1.next else: l.next = ListNode(l2.val) l2 = l2.next l = l.next l.next = l1 or l2 return s.next
def deleteDuplicates(self, head: ListNode) -> ListNode: s = ListNode('') s.next = head x = y = s while y and y.next: while y.next and y.val == y.next.val: y = y.next y = y.next if (not y) or (not y.next) or (not y.val == y.next.val): x.next = y x = x.next return s.next
def deleteDuplicates(self, head: ListNode) -> ListNode: s = ListNode(0) s.next = head x = y = head while y and y.next: y = y.next if x.val < y.val: x.next = y x = x.next if x and x.next: x.next = None return s.next
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode: s = ListNode(0) s.next = head x = s z = s for i in range(n): x = x.next while x.next: x = x.next z = z.next z.next = z.next.next return s.next
def removeElements(self, head: ListNode, val: int) -> ListNode: s = ListNode('') s.next = head prev, node = s, head while node: if node.val == val: # skip node, hold prev prev.next = node.next else: # move prev to forward prev = node node = node.next return s.next
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode: n = s = ListNode(0) k = 0 while l1 or l2 or k > 0: if l1: k += l1.val l1 = l1.next if l2: k += l2.val l2 = l2.next n.next = ListNode(k % 10) k //= 10 n = n.next return s.next
def partition(self, head: ListNode, x: int) -> ListNode: p = l = ListNode('') q = g = ListNode('') z = head while z: if z.val < x: l.next = z l = l.next else: g.next = z g = g.next z = z.next l.next = q.next g.next = None return p.next
def reverseList(self, head: ListNode) -> ListNode: """Iterative Solver 1. """ s = ListNode(0) s.next = head if s.next and s.next.next: x = s.next y = s.next.next while y: h = s.next z = y.next s.next = y y.next = h x.next = z y = x.next return s.next
def sortList(self, head: ListNode) -> ListNode: """merge sort on linked list. iterate over linked list, say, s -> head -> ...-> .. k: number of every k nodes are sorted, k = 1, 2, .. n, e.g., s -> l -> .. -> x -> .. -> y -> .. -> r -> .. --------- --------- k nodes k nodes merge k nodes from x and y, so every 2k nodes are sorted, l and r are the left and right node for next x, y pair """ s = ListNode('') s.next = head # linked list length # it is ok to get n from k = 1 case, but this way is more cleaner x, n = s, 0 while x.next: x = x.next n += 1 # merge sort k = 1 while k < n: l = s while l.next: x = l.next # move k step forward, break link so x -> ... -> None, with lengh k y = x for _ in range(k - 1): if y is not None: y = y.next if y is not None: h = y y = y.next h.next = None # move k step forward, break link so y -> ... -> None, with lengh k r = y for _ in range(k - 1): if r is not None: r = r.next if r is not None: h = r r = r.next h.next = None # merge and connect, so that l -> mergeSorted(x, y) -> r if y is not None and not x == y: l = self.merge(l, x, y, r) else: break k *= 2 return s.next
def oddEvenList(self, head: ListNode) -> ListNode: """TC: O(N), SC: O(1). """ # sentinel head for odd and even so, se = ListNode(''), ListNode('') xo, xe = so, se while head: xo.next = head xo = xo.next if head.next: head = head.next xe.next = head xe = xe.next head = head.next xo.next = se.next xe.next = None return so.next
def plusOne(self, head: ListNode) -> ListNode: # sentinel node s = ListNode('') s.next = head # create prev along the way node = s while node.next: node.next.prev = node node = node.next # plus one on the node from tail while True: if node.val < 9: node.val += 1 break else: node.val = 0 node = node.prev if node.val == '': x = ListNode(1) x.next = node.next node.next.prev = x node.next = x x.prev = node break return s.next
def reverseList(self, head: ListNode) -> ListNode: """Recursive Solver. """ if head and head.next: x = self.reverseList(head.next) head.next.next = head head.next = None return x else: return head
def deleteNodes(self, head: ListNode, m: int, n: int) -> ListNode: s = ListNode('') s.next = head prev, node = s, head while node: count = 0 while node and count < m: prev, node = node, node.next count += 1 hold = prev if count == m: count = 0 while node and count < n: prev, node = node, node.next count += 1 prev = hold # passthrough prev.next = node return s.next
def insertionSortList(self, head: ListNode) -> ListNode: # INTEGER_MIN s = ListNode(-2147483648) s.next = head # insertion sort x = head while x and x.next: y = x.next if y.val < x.val: z = s while not z == x: if y.val < z.next.val: x.next = y.next y.next = z.next z.next = y break z = z.next else: x = x.next return s.next
def isPalindrome(self, head: ListNode) -> bool: """Two pass, 1st reach to tail and create reverse link along the way, 2nd two pointers head and tail. An alternative approach is 1st pass two pointers slow (1 step each iteration) and fast (2 step each iteration), and when fast reach to the tail, slow reach to middle, then reverse along the way slow from middle to the tail, and then 2nd pass two pointers head and tail and comparison along the way. However, this alternative approach need more caution on corner cases, odd/even middle, empty linked list and etc. """ # 1st pass s = ListNode('') s.next = head prev, node = s, head while node: node.prev = prev prev = node node = node.next t = ListNode('') prev.next = t t.prev = prev # 2nd pass x, y = s.next, t.prev # equality test use x is y (kind like x === y in javascript) instead of x == y, strict for reference equality, # because in the config.listnode, class ListNode defined __eq__() as value equal for general purpose equality. while not (x is y or x.prev is y): if not x.val == y.val: return False else: x = x.next y = y.prev return True
def mergeKLists(self, lists: List[ListNode]) -> ListNode: k = len(lists) h = [l for l in lists if l] heapq.heapify(h) s = ListNode(0) x = s while h: v = heapq.heappop(h) x.next = v x = x.next if v.next: heapq.heappush(h, v.next) return s.next
def reverseKGroup(self, head: ListNode, k: int) -> ListNode: """Keep Two Pairs, prev and curr, prev group tail and curr group head. """ s = prevK = ListNode(0) s.next = holdK = currK = head i = 1 while currK: currK = currK.next if i % k == 0: prev, curr = currK, holdK for _ in range(k): curr.next, curr, prev = prev, curr.next, curr prevK.next, prevK, holdK = prev, holdK, currK i += 1 return s.next
def removeZeroSumSublists(self, head: ListNode) -> ListNode: # O(N), one pass, in-place # s: sentinel node s = node = ListNode(0) s.next = head # consecutive sum 0 <=> prefix sum seen prefix, seen = 0, OrderedDict() while node: prefix += node.val prev = seen.get(prefix, node) while prefix in seen: seen.popitem() seen[prefix] = prev prev.next = node.next node = node.next return s.next
def swapPairs(self, head: ListNode) -> ListNode: s = ListNode(0) s.next = head x = s while x.next and x.next.next: z = ListNode(x.next.val) x.next = x.next.next x = x.next z.next = x.next x.next = z x = x.next return s.next