-
Notifications
You must be signed in to change notification settings - Fork 0
141. Linked List Cycle #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8711e53
b743866
3963b5a
d65d37d
216ab47
2a5b8bf
dd7b06a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
# 141. Linked List Cycle | ||
|
||
## Link | ||
|
||
https://leetcode.com/problems/linked-list-cycle/ | ||
|
||
## How to work on each step | ||
|
||
- Step 1: 答えを見ずに 5 分以内に解く。わからなかったら答えを見て、開始から答えを見ないで 5 分以内に正解になるところまで行う。 | ||
- Step 2: 本協会メンバーや LeetCode の過去解答を参考にしつつ、コードを見やすくする形で整える。 | ||
- Step 3: 全部消して、10 分以内にエラーを一度も出さずに正解するのを 3 回続けて行う。 | ||
- Step 4: いただいたレビューをもとに、コードを整える。 | ||
|
||
## Comments | ||
|
||
### Step 1 | ||
5分以内にはまったく解けなかった。 | ||
なんとなく一度訪れた値を保存しておいて、再度訪れたら true を返すイメージだけ思いついたが、表現方法が分からずタイムアウト。 | ||
|
||
調べると自分がイメージしていたのは、再帰関数で実現出来そうだったので、再帰関数で対応してみた。 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 何を見たか、リファレンスへのリンクがあると比較しやすいかなと思いました。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @brood0783 |
||
|
||
### Step 2 | ||
|
||
調べたらTwo pointer (フロイドのうさぎとかめ)と言うアルゴリズムを見つけた。 | ||
ただ、[常識ではない](https://discord.com/channels/1084280443945353267/1195700948786491403/1195944696665604156)らしい。 | ||
個人的にも初見でこれを見たら実装者に質問しそうなので再帰関数を選択することにした。 | ||
|
||
再帰関数は内部関数を無くすことでよりシンプルな実装に変更。 | ||
|
||
### Step 3 | ||
ここまでで頭の中が整理されたようで意外とすんなりStep3は通過した。 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# Definition for singly-linked list. | ||
# class ListNode(object): | ||
# def __init__(self, x): | ||
# self.val = x | ||
# self.next = None | ||
|
||
class Solution(object): | ||
def hasCycle(self, head): | ||
def depthFirstSearch(node, visited): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. inner function とするなら、 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ryosuketc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 手法を関数名にすることはあまりないので、 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ryosuketc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 書類の整理のときにフォルダーに書く名前は「平成25年度取締役会議事録」などであって、中の構造、たとえば「時系列順」ではないですよね。 student_names = recursion(student_names) こう書いてあったら recursion の中を解読に行きますね。探索が一段階で済めばいいですけど。 student_names = sorted(student_names) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @oda
確かにです! |
||
if not node: | ||
return False | ||
if node in visited: | ||
return True | ||
|
||
visited.add(node) | ||
return depthFirstSearch(node.next, visited) | ||
|
||
return depthFirstSearch(head, set()) | ||
Comment on lines
+7
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. たしかに再帰で書けますね。思いつかなかったので、おもしろいな〜と思いました。 |
||
|
||
#### レビュー反映 | ||
|
||
class RevisedSolution(object): | ||
def hasCycle(self, head): | ||
visited = set() | ||
def has_cycle_helper(node): | ||
if not node: | ||
return False | ||
if node in visited: | ||
return True | ||
|
||
visited.add(node) | ||
return has_cycle_helper(node.next) | ||
|
||
return has_cycle_helper(head) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Definition for singly-linked list. | ||
# class ListNode(object): | ||
# def __init__(self, x): | ||
# self.val = x | ||
# self.next = None | ||
|
||
class TwoPointerSolution(object): | ||
def hasCycle(self, head): | ||
if not head or not head.next: | ||
return False | ||
|
||
slow = head | ||
fast = head.next | ||
|
||
while slow != fast: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 今回の場合、 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @huyfififi
|
||
if not fast or not fast.next: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. notはfalsy判定なので、is Noneの方が安全かなと思いました。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @brood0783 |
||
return False | ||
slow = slow.next | ||
fast = fast.next.next | ||
|
||
return True | ||
|
||
class RecursionSolution(object): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これは再帰ではないですね There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ryosuketc |
||
def hasCycle(self, head): | ||
visited = set() | ||
node = head | ||
while node: | ||
if node in visited: | ||
return True | ||
visited.add(node) | ||
node = node.next | ||
return False | ||
|
||
#### レビュー反映 | ||
|
||
class RevisedTwoPointerSolution(object): | ||
def hasCycle(self, head): | ||
if head is None or head.next is None: | ||
return False | ||
|
||
slow = head | ||
fast = head.next | ||
|
||
while slow is not fast: | ||
if fast is None or fast.next is None: | ||
return False | ||
slow = slow.next | ||
fast = fast.next.next | ||
|
||
return True | ||
|
||
class HashSetSolution(object): | ||
def hasCycle(self, head): | ||
visited = set() | ||
node = head | ||
while node: | ||
if node in visited: | ||
return True | ||
visited.add(node) | ||
node = node.next | ||
return False |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
class RecursionSolution(object): | ||
def hasCycle(self, head): | ||
visited = set() | ||
node = head | ||
while node: | ||
if node in visited: | ||
return True | ||
visited.add(node) | ||
node = node.next | ||
return False | ||
|
||
#### レビュー反映 | ||
|
||
class HashSetSolution(object): | ||
def hasCycle(self, head): | ||
visited = set() | ||
node = head | ||
while node: | ||
if node in visited: | ||
return True | ||
visited.add(node) | ||
node = node.next | ||
return False |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
class Solution(object): | ||
def hasCycle(self, head): | ||
visited = set() | ||
node = head | ||
while node: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. broodさんがご指摘の通り、また私の class ListNode:
def __init__(self, x):
self.val = x
self.next = None
def __bool__(self):
return self.val > 0
if ListNode(1):
print(bool(ListNode(1))) # True
if not ListNode(0):
print(bool(ListNode(0))) # False There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
コメントありがとうございます!
この「定義次第で条件式が予期せぬ挙動をする」部分が普段意識出来ておらず抜けがちなようです! |
||
if node in visited: | ||
return True | ||
visited.add(node) | ||
node = node.next | ||
return False | ||
|
||
## 指摘反映 | ||
|
||
class Solution(object): | ||
def hasCycle(self, head): | ||
visited = set() | ||
node = head | ||
while node is not None: | ||
if node in visited: | ||
return True | ||
visited.add(node) | ||
node = node.next | ||
return False | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
再帰で書くことはとてもよいことですが、再帰は深さの限界があることが多いので状況からして問題がないかを見積もりましょう。
もちろん、他にもいろいろなよしあしがあるので徐々に意識していきましょう。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.uvguf4c3q02d
最終的には、どのやりかたもいいところ悪いところがあるが、その中ではこれが今のところよいかなと思えるようになることです。
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oda
コメントありがとうございます!
LeetCode 141: Linked List Cycle の制約
上記の場合は深さは最大O(10^4)になる認識です。
調べたところ、leetcodeの深さは最大550000まで大丈夫なようなのでleetcode上では大丈夫そうですが、
ローカルのMacの場合1000が限界と言う内容もあるのでptyhonでの再帰は現実的ではないのかな?と思いました。
https://www.reddit.com/r/leetcode/comments/12xy7f9/extraordinarily_high_system_recursion_limit_for/?tl=ja