Skip to content
Open
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
85 changes: 85 additions & 0 deletions memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
## 今回解いた問題と次に解く問題
- 今回解いた問題: 141. Linked List Cycle(https://leetcode.com/problems/linked-list-cycle?envType=problem-list-v2&envId=xo2bgr0r)
- 次に解く問題: 20. Valid Parentheses(https://leetcode.com/problems/valid-parentheses?envType=problem-list-v2&envId=xo2bgr0r)
## Step 1
### 考えたこと
- フロイドの循環検出法を見たことがあったが、とりあえず一度訪れたnodeをsetに保持しておいて、毎回確認する方法が確実なので書いてみる。時間計算量はO(n), 空間計算量はsetを用意するのでO(n)
- setの中にclassを入れることができるかわからなかったので、確認した。
- `while True`は停止しないときが怖いので、使いたくないと感じたが、パッとループを回す方法が思いつかなかったので一度書いてみた。
-
```python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
visited_node = set()
current_node = head

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

current という単語に、あまり情報がないように思いました。単に node だけで十分だと思います。

current/previous/next と対比する場合には、付けても良いと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます!納得しました。形容詞を使う際は、対比するものがあるかどうかを意識して、対比先がなければ使わないようにしてみようと思います。

if head is None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

自分なら、コーナーケースで early return する場合、関数の一番上に書くと思います。理由は、関数宣言と early return の間に書かれた内容を、 early return のロジックを読む間、読み手が短期記憶に保持し続けなければならないためです。これは短期記憶の要領の無駄遣いになり、読み手にとって不要な認知負荷になると思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。納得しました。early returnの場合は関数の最初で書くように意識してみます。

return False
while True:
if current_node.next is None:
return False
elif current_node.next in visited_node:
return True
else:
visited_node.add(current_node)
current_node = current_node.next
```
## Step 2
### 読んだコード
- https://discord.com/channels/1084280443945353267/1195700948786491403/1195944696665604156
- https://github.com/tk-hirom/Arai60/pull/1
- https://github.com/katayude/yamaguchiLeetCode/pull/1

### 考えたこと
- Listのinの確認は、線形で舐めるのでできる限りsetで確認をしたい。
- `while head`で最初のifの分岐をなくして可読性を上げられる可能性がある。

```python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
visited = set()
while head:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

こちらのコメントをご参照ください。
ksaito0629/leetcode_arai60#1 (comment)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。納得しました。boolの評価はis Noneなどの形で行うように意識します。

if head in visited:
return True
else:
visited.add(head)
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

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます。headが動くことに違和感があるという点に納得しました。連結リストを扱う際はheadは動かさず、別の変数に格納してから扱おうと思います。

return False
```

## Step 3(フロイドの循環検出法で書いてみる)
- fast, slowの2つのポインタを用意して、fastは2ノードずつ進む。slowは1ノードずつ進む。fastとslowが同じノードを指していたら、循環が存在する。
- 利点はsetを用意しなくていいので空間計算量がO(1)になること
- 入力が空のケースをどう組み込むかを考えられず、一度間違ったコードを書いてしまった。(fastの初期値をhead.nextにしてしまった。)ポインタを動かしてから同じかどうかを評価すればいい。
- fast.nextがNoneだとfast.next.nextにアクセスできないケースを考えず、`while fast`で評価してしまった。
- 総じて考慮すべき条件が多いので、元のsetのやり方で書きたいと思った。(空間計算量O(n)が許されるなら。)

```python
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None

class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
fast = head
slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if fast == slow:
return True
return False
```