From 337a795ad0421f74dea836bf5cddc9e13972cd73 Mon Sep 17 00:00:00 2001 From: Dan Buch Date: Sat, 21 Oct 2023 08:23:14 -0400 Subject: [PATCH] Linked list sorting (?) --- leetcode/.gitignore | 1 + leetcode/pyproject.toml | 3 ++- leetcode/stdlib.py | 9 +++++++++ leetcode/stuff.py | 39 +++++++++++++++++++++++++++++++++++++++ leetcode/test_stuff.py | 25 +++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 leetcode/.gitignore create mode 100644 leetcode/stdlib.py diff --git a/leetcode/.gitignore b/leetcode/.gitignore new file mode 100644 index 0000000..7a6353d --- /dev/null +++ b/leetcode/.gitignore @@ -0,0 +1 @@ +.envrc diff --git a/leetcode/pyproject.toml b/leetcode/pyproject.toml index f19d787..9de7a9e 100644 --- a/leetcode/pyproject.toml +++ b/leetcode/pyproject.toml @@ -25,7 +25,8 @@ classifiers = [ "Programming Language :: Python :: Implementation :: PyPy", ] dependencies = [ - "ipython" + "ipython", + "ipdb" ] [project.urls] diff --git a/leetcode/stdlib.py b/leetcode/stdlib.py new file mode 100644 index 0000000..cdd4e9e --- /dev/null +++ b/leetcode/stdlib.py @@ -0,0 +1,9 @@ +import typing + + +class ListNode: + """ListNode is the leetcode "standard library" type used in linked lists""" + + def __init__(self, val=0, next: typing.Optional["ListNode"] = None): # no qa + self.val = val + self.next = next diff --git a/leetcode/stuff.py b/leetcode/stuff.py index 508338c..6c1f3ea 100644 --- a/leetcode/stuff.py +++ b/leetcode/stuff.py @@ -1,5 +1,7 @@ import typing +import stdlib + def yep(s: str) -> bool: return s.strip().lower().startswith("y") @@ -158,3 +160,40 @@ class MinStack: def getMin(self) -> int: # no qa return self._min[-1] + + +def linked_list_to_list(head: stdlib.ListNode | None) -> list[int]: + seen: set[int] = set() + ret: list[int] = [] + + while head is not None: + if hash(head) in seen: + return ret + + seen.add(hash(head)) + ret.append(head.val) + head = head.next + + return ret + + +def sort_linked_list(head: stdlib.ListNode | None) -> stdlib.ListNode | None: + by_val: list[tuple[int, stdlib.ListNode]] = [] + ret: stdlib.ListNode | None = None + + while head is not None: + by_val.append((head.val, head)) + head = head.next + + cur = ret + + for _, node in sorted(by_val): + if cur is None: + cur = ret = stdlib.ListNode(node.val) + continue + + next_node = stdlib.ListNode(node.val) + cur.next = next_node + cur = next_node + + return ret diff --git a/leetcode/test_stuff.py b/leetcode/test_stuff.py index 87418a6..bf26267 100644 --- a/leetcode/test_stuff.py +++ b/leetcode/test_stuff.py @@ -1,6 +1,7 @@ import pytest import stuff +import stdlib @pytest.mark.parametrize( @@ -77,3 +78,27 @@ def test_min_stack(ops: list[tuple[str] | tuple[str, int]], expected: list[int | returned.append(getattr(inst, method)(arg)) assert returned == expected + + +@pytest.mark.parametrize( + ("head", "expected"), + [ + (None, None), + ( + stdlib.ListNode( + 4, stdlib.ListNode(2, stdlib.ListNode(1, stdlib.ListNode(3))) + ), + stdlib.ListNode( + 1, stdlib.ListNode(2, stdlib.ListNode(3, stdlib.ListNode(4))) + ), + ), + ], +) +def test_sort_linked_list(head: stdlib.ListNode | None, expected: stdlib.ListNode | None): + if head is None: + assert stuff.sort_linked_list(head) == expected + return + + assert stuff.linked_list_to_list( + stuff.sort_linked_list(head) + ) == stuff.linked_list_to_list(expected)