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
95 changes: 95 additions & 0 deletions Arai60/LinkedList/answer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# 問題文

# Step1

かかった時間:20min

思考ログ:
- 問題を理解する。
- 前回とは異なり、重複があるものを”全て”削除する。
- 入出力:ともに連結リスト
- 計算量:時間…O(N) 空間…O(1)
- ループの中で、2つのポインタの値を比較する。
- 値が異なる場合は隣にいく。
- 値が一致した場合は、先頭ノードだけ隣へ更新。再度比較して異なった場合は後方ノードを先頭に、先頭はその隣に移動。
- 解けなかったので解法をみた。最初のノード(head)も重複している場合、それを削除する処理が必要。ダミーを使用することで先頭ノードの削除処理とそれ以外のノードの削除処理を同じ方法で扱える。ダミーを置くことに気づけなかった。
```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

sentinel という単語を使うのも良いと思います。
hroc135/leetcode#4 (comment)

dummy.next = head
previous_node = dummy
current_node = head

while current_node:
while current_node.next and current_node.val == current_node.next.val:
current_node = current_node.next
if previous_node.next == current_node:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

if 文の条件が True のときと False のときのどちらの時に値が重複しているのか、直感的でないように感じました。また、変数を previous_node と current_node の 2 つ使うのではなく、 1 つだけにしたほうがシンプルだと感じました。以下のようなコードはいかがでしょうか?

node = dummy
while node and node.next and node.next.next:
    if node.next.val != node.next.next.val:
        # 重複していない場合
        # early return する。
        node = node.next
        continue

    # 重複している場合
    value = node.next.val
    while node.next and node.next.val == value:
        node.next = node.next.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.

たしかにご提示のコードのほうが直感的だなと感じました。

previous_node = previous_node.next
else:
previous_node.next = current_node.next
current_node = current_node.next
return dummy.next
```

# Step2
かかった時間:min

思考ログ
- 他の方のコードやコメントを読む
- [型ヒントでnodeが自明](https://github.com/hrkh/leetcode/pull/5/files#r1676086915)
- [かといってcurrentという名前は諸説ある](https://github.com/canisterism/leetcode/pull/4#discussion_r1688679810)
- [マジックナンバー(意味のない数字)は避けるべき](https://github.com/goto-untrapped/Arai60/pull/43#discussion_r1695376875)
- nodeが自明なのはそうだなって思ったので名前からnodeを消して実装をしてみる。こっちのほうが見やすいかも

```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(None)
dummy.next = head
previous = dummy
current = head

while current:
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の初期化時にcurrent = previous = dummyとしておくと、walrus演算子を使ってcurrent := current.nextと書くことができ、ループ変数を進める処理をわかりやすくできます(python3.8以降)
好みもありますが参考まで。

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.

walrus演算子で変数への代入と変数の使用を同時に行えるのですね。適切に使えるとコードをすっきりできそうだなと思いました。ありがとうございます。

while current.next and current.val == current.next.val:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

実際はO(n)でできているのですが、whileが二重になっているのでぱっと見O(n^2)になっていることがなんとなく気になります。二重whileを使わない方法としては、duplicatedなどのフラグを用意してやるとできると思います。

current = current.next
if previous.next == current:
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Step1の指摘と類似ですが、ここの分岐は読み飛ばしが発生したかしていないかなので、もう少しわかりやすくできると嬉しいですね。前のwhileの条件と逆になるのが見にくいのかも?と思いました。
代入回数が増えてしまいますが、elseを省略することはできます。

            while current.next and current.val == current.next.val:
                current = current.next
                previous.next = current.next
            if previous.next == current:
                previous = 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.

ブロックがすくないこちらのほうが私も見やすいと感じました。

previous = previous.next
else:
previous.next = current.next
current= current.next
return dummy.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.

最適解ではありませんが、自分はHashMapでカウントしていく解法でも解きました。
Mike0121/LeetCode@5e139d5

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の長さに依存するのでn
- 基本:`head`が空ないし要素が単一のときに`head`を返す
- 再帰:重複があったときの処理

```python
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head or not head.next:
return head

if head.val == head.next.val:
while head.next and head.val == head.next.val:
head = head.next
return self.deleteDuplicates(head.next)
else:
head.next = self.deleteDuplicates(head.next)
return head
```

# Step3
かかった時間: 3min

Step2のコードを書き直し⇒Subを何回かした。


# Step 4
- レビューを持って修正を行う

```python


```
22 changes: 9 additions & 13 deletions answer_template.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,38 @@
# 問題文
https://leetcode.com/problems/linked-list-cycle-ii/description/

# Step1

かかった時間:10min
かかった時間:min

思考ログ:
- 問題を理解する。
- 入出力ともに`Optional[ListNode]`。141との違いはReturnが変わっている
- 前回は`bool`でよかったが今回はサイクルありならサイクルが始まるListNodeを、そうでないならNoneを返す。
- とりあえずハッシュテーブルを利用する方法でやってみる。空間計算量はO(n)
- ノードの数がnであるとき、visitedリストも最大でn個の要素を持つため。

-
```python

```
疑問点:
- setでもリストでもとおったが、どっちのほうがよいのだろうか?
-
-
参考リンク
-
# Step2
かかった時間:20min
かかった時間:min

思考ログ
- まずはハッシュテーブルを再実装し、コードの改良箇所をみつける。
-

```python

```

- フロイドの循環検出法を実装したがTLE。解法をみた(下記は通らなかった実装)
-
```python

```

# Step3
かかった時間: 5min
上記を書き直し、実装。
かかった時間: min


```python

Expand Down