From ed4100811a3813ae383bd30eae851c53faa8aaee Mon Sep 17 00:00:00 2001 From: tom4649 Date: Thu, 25 Jun 2026 06:35:45 +0900 Subject: [PATCH 1/2] step1,2 --- 0148.Sort-List/memo.md | 24 ++++++++++ 0148.Sort-List/step1.py | 54 +++++++++++++++++++++ 0148.Sort-List/step1_revised.py | 56 ++++++++++++++++++++++ 0148.Sort-List/step2_constant_space.py | 66 ++++++++++++++++++++++++++ 4 files changed, 200 insertions(+) create mode 100644 0148.Sort-List/memo.md create mode 100644 0148.Sort-List/step1.py create mode 100644 0148.Sort-List/step1_revised.py create mode 100644 0148.Sort-List/step2_constant_space.py diff --git a/0148.Sort-List/memo.md b/0148.Sort-List/memo.md new file mode 100644 index 0000000..b54295d --- /dev/null +++ b/0148.Sort-List/memo.md @@ -0,0 +1,24 @@ +# 148. Sort List + +## step1 +22mかかった。先頭からスキャンするListNodeの性質上、マージソートが良いだろう。 + +関数mergeの最後でhead.next = Noneをつけずにメモリエラーが生じた。これは答えの確認時に起きたのではないかと思われる。 + +空間計算量が O(log n) + +## step2 +https://github.com/potrue/leetcode/pull/69 + +再帰を使わずにマージを行っている。なるほど。 + +確かにlistに値を格納してしまえば標準ライブラリが使えるけど問題の意図を汲んでいない気がする。 + +> Follow up: Can you sort the linked list in O(n logn) time and O(1) memory (i.e. constant space)? + +上の解法がこの答えになっている + +リストをカットしないものを書く + +## step3 +TODO diff --git a/0148.Sort-List/step1.py b/0148.Sort-List/step1.py new file mode 100644 index 0000000..4133849 --- /dev/null +++ b/0148.Sort-List/step1.py @@ -0,0 +1,54 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if head is None: + return None + + def merge(head1, head2, n1, n2): + dummy = ListNode() + head = dummy + index1 = 0 + index2 = 0 + node1 = head1 + node2 = head2 + while index1 < n1 or index2 < n2: + if index2 >= n2 or (index1 < n1 and node1.val < node2.val): + head.next = node1 + head = head.next + node1 = node1.next + index1 += 1 + else: + head.next = node2 + head = head.next + node2 = node2.next + index2 += 1 + head.next = None + + return dummy.next + + def merge_sort(head, length): + if length == 1: + return head + + half_length = length // 2 + second_head = head + for _ in range(half_length): + second_head = second_head.next + + first_head_sorted = merge_sort(head, half_length) + second_head_sorted = merge_sort(second_head, length - half_length) + return merge( + first_head_sorted, second_head_sorted, half_length, length - half_length + ) + + node = head + length = 0 + while node is not None: + length += 1 + node = node.next + + return merge_sort(head, length) diff --git a/0148.Sort-List/step1_revised.py b/0148.Sort-List/step1_revised.py new file mode 100644 index 0000000..1e43331 --- /dev/null +++ b/0148.Sort-List/step1_revised.py @@ -0,0 +1,56 @@ +# Definition for singly-linked list. +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + +class Solution: + def sortList(self, head: ListNode | None) -> ListNode | None: + if head is None: + return None + + def merge(head1, head2, length1, length2): + dummy = ListNode() + head = dummy + index1 = 0 + index2 = 0 + node1 = head1 + node2 = head2 + while index1 < length1 or index2 < length2: + if index2 >= length2 or (index1 < length1 and node1.val < node2.val): + head.next = node1 + head = head.next + node1 = node1.next + index1 += 1 + else: + head.next = node2 + head = head.next + node2 = node2.next + index2 += 1 + head.next = None + + return dummy.next + + def merge_sort(head, length): + if length == 1: + return head + + half_length = length // 2 + second_head = head + for _ in range(half_length): + second_head = second_head.next + + first_head_sorted = merge_sort(head, half_length) + second_head_sorted = merge_sort(second_head, length - half_length) + return merge( + first_head_sorted, second_head_sorted, half_length, length - half_length + ) + + node = head + length = 0 + while node is not None: + length += 1 + node = node.next + + return merge_sort(head, length) diff --git a/0148.Sort-List/step2_constant_space.py b/0148.Sort-List/step2_constant_space.py new file mode 100644 index 0000000..358febd --- /dev/null +++ b/0148.Sort-List/step2_constant_space.py @@ -0,0 +1,66 @@ +# Definition for singly-linked list. +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + +class Solution: + def sortList(self, head: ListNode | None) -> ListNode | None: + if head is None or head.next is None: + return head + + def merge(head1, head2, length1, length2): + dummy = ListNode() + head = dummy + index1 = 0 + index2 = 0 + node1 = head1 + node2 = head2 + while index1 < length1 or index2 < length2: + if index2 >= length2 or (index1 < length1 and node1.val < node2.val): + head.next = node1 + head = head.next + node1 = node1.next + index1 += 1 + else: + head.next = node2 + head = head.next + node2 = node2.next + index2 += 1 + head.next = None + + return dummy.next + + def skip_nodes(head, n): + count = 0 + for _ in range(n): + if head is None: + return None, count + count += 1 + head = head.next + return head, count + + node = head + length = 0 + while node is not None: + length += 1 + node = node.next + + sorted_length = 1 + dummy = ListNode() + dummy.next = head + prev_merged_tail = dummy + while sorted_length < length: + prev_merged_tail = dummy + next_head = dummy.next + while next_head is not None: + first_head = next_head + second_head, length1 = skip_nodes(first_head, sorted_length) + next_head, length2 = skip_nodes(second_head, sorted_length) + prev_merged_tail.next = merge(first_head, second_head, length1, length2) + prev_merged_tail, _ = skip_nodes(prev_merged_tail, length1 + length2) + sorted_length *= 2 + prev_merged_tail.next = None + + return dummy.next From 8b76f2e8027617bae16102fe13f435dbe13d52ad Mon Sep 17 00:00:00 2001 From: tom4649 Date: Sun, 28 Jun 2026 07:00:46 +0900 Subject: [PATCH 2/2] Add suggested changes --- 0148.Sort-List/step1_revised.py | 12 ++-- .../step2_constant_space_revised.py | 66 +++++++++++++++++++ 2 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 0148.Sort-List/step2_constant_space_revised.py diff --git a/0148.Sort-List/step1_revised.py b/0148.Sort-List/step1_revised.py index 1e43331..6d883c8 100644 --- a/0148.Sort-List/step1_revised.py +++ b/0148.Sort-List/step1_revised.py @@ -12,23 +12,23 @@ def sortList(self, head: ListNode | None) -> ListNode | None: def merge(head1, head2, length1, length2): dummy = ListNode() - head = dummy + tail = dummy index1 = 0 index2 = 0 node1 = head1 node2 = head2 while index1 < length1 or index2 < length2: if index2 >= length2 or (index1 < length1 and node1.val < node2.val): - head.next = node1 - head = head.next + tail.next = node1 + tail = tail.next node1 = node1.next index1 += 1 else: - head.next = node2 - head = head.next + tail.next = node2 + tail = tail.next node2 = node2.next index2 += 1 - head.next = None + tail.next = None return dummy.next diff --git a/0148.Sort-List/step2_constant_space_revised.py b/0148.Sort-List/step2_constant_space_revised.py new file mode 100644 index 0000000..e29b2f2 --- /dev/null +++ b/0148.Sort-List/step2_constant_space_revised.py @@ -0,0 +1,66 @@ +# Definition for singly-linked list. +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + +class Solution: + def sortList(self, head: ListNode | None) -> ListNode | None: + if head is None or head.next is None: + return head + + def merge(head1, head2, length1, length2): + dummy = ListNode() + tail = dummy + index1 = 0 + index2 = 0 + node1 = head1 + node2 = head2 + while index1 < length1 or index2 < length2: + if index2 >= length2 or (index1 < length1 and node1.val < node2.val): + tail.next = node1 + tail = tail.next + node1 = node1.next + index1 += 1 + else: + tail.next = node2 + tail = tail.next + node2 = node2.next + index2 += 1 + tail.next = None + + return dummy.next + + def skip_nodes(start_node, n): + count = 0 + for _ in range(n): + if start_node is None: + return None, count + count += 1 + start_node = start_node.next + return start_node, count + + node = head + length = 0 + while node is not None: + length += 1 + node = node.next + + sorted_length = 1 + dummy = ListNode() + dummy.next = head + prev_merged_tail = dummy + while sorted_length < length: + prev_merged_tail = dummy + next_head = dummy.next + while next_head is not None: + first_head = next_head + second_head, length1 = skip_nodes(first_head, sorted_length) + next_head, length2 = skip_nodes(second_head, sorted_length) + prev_merged_tail.next = merge(first_head, second_head, length1, length2) + prev_merged_tail, _ = skip_nodes(prev_merged_tail, length1 + length2) + sorted_length *= 2 + prev_merged_tail.next = None + + return dummy.next