From dc1c453f5a060a94eb06b3cbb3dd2fc4e2fb68ce Mon Sep 17 00:00:00 2001 From: tom4649 Date: Fri, 26 Jun 2026 06:15:31 +0900 Subject: [PATCH 1/3] step1,2 --- 0019.Remove-Nth-Node-From-End-of-List/memo.md | 27 ++++++++++++++++++ .../step1_one_pass.py | 25 +++++++++++++++++ .../step1_two_pass.py | 28 +++++++++++++++++++ .../step2.py | 27 ++++++++++++++++++ 4 files changed, 107 insertions(+) create mode 100644 0019.Remove-Nth-Node-From-End-of-List/memo.md create mode 100644 0019.Remove-Nth-Node-From-End-of-List/step1_one_pass.py create mode 100644 0019.Remove-Nth-Node-From-End-of-List/step1_two_pass.py create mode 100644 0019.Remove-Nth-Node-From-End-of-List/step2.py diff --git a/0019.Remove-Nth-Node-From-End-of-List/memo.md b/0019.Remove-Nth-Node-From-End-of-List/memo.md new file mode 100644 index 0000000..9b24f3d --- /dev/null +++ b/0019.Remove-Nth-Node-From-End-of-List/memo.md @@ -0,0 +1,27 @@ +# 19. Remove Nth Node From End of List + +## step1 +一巡して長さを求めて、もう一巡して削除を行う。8mぐらい。今回はミスがなかった。 + +削除したNodeのnextをNoneに変更した。メモリリークを明示的に防ぐためである。 + +制約も小さく、解くだけなら簡単な問題なので、他の方針も考える。 + +> Follow up: Could you do this in one pass? + +hashmapを使えば実現できる + +nth がendから数えたものなので、一度最後まで走査しないと削除が実行できない。これ以外の方針は思いつかない。 + +## 他の人のコード + +https://github.com/thonda28/leetcode/pull/18 + +slowとfastを使うのか、なるほど。自分で思いつきたいところだった。 + +> step1のslow, fastの方が(個人的には)読みやすく感じました + + +このコードでは上述のメモリリークの対策はしていないようだが、した方が良いように思う + +## step2 diff --git a/0019.Remove-Nth-Node-From-End-of-List/step1_one_pass.py b/0019.Remove-Nth-Node-From-End-of-List/step1_one_pass.py new file mode 100644 index 0000000..3de1f17 --- /dev/null +++ b/0019.Remove-Nth-Node-From-End-of-List/step1_one_pass.py @@ -0,0 +1,25 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: + index_to_node = {} + index = 0 + node = head + while node is not None: + index_to_node[index] = node + node = node.next + index += 1 + + index_from_start = index - n + if index_from_start < 0: + raise ValueError(f"n is too large: {n}") + if index_from_start == 0: + return head.next + + index_to_node[index_from_start - 1].next = index_to_node[index_from_start].next + index_to_node[index_from_start].next = None + + return head diff --git a/0019.Remove-Nth-Node-From-End-of-List/step1_two_pass.py b/0019.Remove-Nth-Node-From-End-of-List/step1_two_pass.py new file mode 100644 index 0000000..cf55d8e --- /dev/null +++ b/0019.Remove-Nth-Node-From-End-of-List/step1_two_pass.py @@ -0,0 +1,28 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]: + count = 0 + node = head + while node is not None: + node = node.next + count += 1 + + index_from_start = count - n + if index_from_start < 0: + raise ValueError(f"n is too large: {n}") + if index_from_start == 0: + return head.next + + node = head + for _ in range(index_from_start - 1): + node = node.next + + temp = node.next.next + node.next.next = None + node.next = temp + + return head diff --git a/0019.Remove-Nth-Node-From-End-of-List/step2.py b/0019.Remove-Nth-Node-From-End-of-List/step2.py new file mode 100644 index 0000000..9b3a002 --- /dev/null +++ b/0019.Remove-Nth-Node-From-End-of-List/step2.py @@ -0,0 +1,27 @@ +# Definition for singly-linked list. +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + + +class Solution: + def removeNthFromEnd(self, head: ListNode | None, n: int) -> ListNode | None: + dummy = ListNode(next=head) + slow = dummy + fast = dummy + for _ in range(n): + fast = fast.next + + if fast is None: + raise ValueError(f"n is too large: {n}") + + while fast.next: + slow = slow.next + fast = fast.next + + removed_node = slow.next + slow.next = removed_node.next + removed_node.next = None + + return dummy.next From df03d231214e04ecdef415bc283885c3976e2e28 Mon Sep 17 00:00:00 2001 From: tom4649 Date: Sat, 27 Jun 2026 08:35:41 +0900 Subject: [PATCH 2/3] Add detailed notes on Python's memory management --- 0019.Remove-Nth-Node-From-End-of-List/memo.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/0019.Remove-Nth-Node-From-End-of-List/memo.md b/0019.Remove-Nth-Node-From-End-of-List/memo.md index 9b24f3d..51d2d6c 100644 --- a/0019.Remove-Nth-Node-From-End-of-List/memo.md +++ b/0019.Remove-Nth-Node-From-End-of-List/memo.md @@ -25,3 +25,20 @@ slowとfastを使うのか、なるほど。自分で思いつきたいところ このコードでは上述のメモリリークの対策はしていないようだが、した方が良いように思う ## step2 + +## pythonのメモリ管理について + +https://daobook.github.io/devguide/garbage_collector.html + +> The main garbage collection algorithm used by CPython is reference counting. + +> ... it would never be cleaned just by simple reference counting. For this reason some additional machinery is needed to clean these reference cycles between objects once they become unreachable. This is the cyclic garbage collector, usually called just Garbage Collector (GC), ... + +> Doubly linked lists are used because they efficiently support most frequently required operations. In general, the collection of all objects tracked by GC are partitioned into disjoint sets, each in its own doubly linked list. + +- 主に参照カウント方式でgcが実装されている +- それだけでは防げない循環参照をcyclic garbage collectorで処理する +- 双方向リストによってオブジェクトの集合ごとに管理されている +- 循環参照の特定: 双方向連結リストにまとめる -> 身内同士の参照カウントをdecrement -> 参照が正のオブジェクトから辿れるオブジェクトをBFSし、参照カウント0のものは1にする -> 参照カウント0のオブジェクトを削除 +- 再帰関数を使わない -> 省メモリ +- 世代別GC: 「新しく作られたオブジェクトのほとんどは、すぐに使われなくなる」仮説を利用する。世代の小さいものを優先的に削除する From 829c3ebf94bf2be72c9c5f216fa8abf56278c780 Mon Sep 17 00:00:00 2001 From: tom4649 Date: Sat, 27 Jun 2026 08:48:22 +0900 Subject: [PATCH 3/3] Add detailed notes on Python's memory management --- 0019.Remove-Nth-Node-From-End-of-List/memo.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/0019.Remove-Nth-Node-From-End-of-List/memo.md b/0019.Remove-Nth-Node-From-End-of-List/memo.md index 51d2d6c..417ea12 100644 --- a/0019.Remove-Nth-Node-From-End-of-List/memo.md +++ b/0019.Remove-Nth-Node-From-End-of-List/memo.md @@ -24,6 +24,8 @@ slowとfastを使うのか、なるほど。自分で思いつきたいところ このコードでは上述のメモリリークの対策はしていないようだが、した方が良いように思う +追記: このコードがなくても参照カウントが0になるためメモリリークは起きないと思われる + ## step2 ## pythonのメモリ管理について