Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions 0148.Sort-List/memo.md
Original file line number Diff line number Diff line change
@@ -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
54 changes: 54 additions & 0 deletions 0148.Sort-List/step1.py
Original file line number Diff line number Diff line change
@@ -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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらのコメントをご参照ください。
https://github.com/yukik8/leetcode/pull/6#discussion_r3287970237

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)
56 changes: 56 additions & 0 deletions 0148.Sort-List/step1_revised.py
Original file line number Diff line number Diff line change
@@ -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()
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 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)
66 changes: 66 additions & 0 deletions 0148.Sort-List/step2_constant_space.py
Original file line number Diff line number Diff line change
@@ -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
66 changes: 66 additions & 0 deletions 0148.Sort-List/step2_constant_space_revised.py
Original file line number Diff line number Diff line change
@@ -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