-
Notifications
You must be signed in to change notification settings - Fork 0
82. Remove Duplicates from Sorted List II.md #4
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
307589f
61596d6
78c6e56
8235a35
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,167 @@ | ||
82. Remove Duplicates from Sorted List II.md | ||
基本的に思考順に書いていく | ||
他の人の発言の引用には「」をつける | ||
|
||
step1 not accepted | ||
```python | ||
class Solution: | ||
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
result = node = head | ||
|
||
while node is not None: | ||
if node.val == node.next.val: | ||
if node.next.val == node.next.next.val: | ||
node = node.next | ||
node.next = node.next.next | ||
node = node.next.next | ||
else: | ||
node = node.next | ||
return result | ||
``` | ||
以下はエラー文。 | ||
```python | ||
AttributeError: 'NoneType' object has no attribute 'val' | ||
^^^^^^^^^^^^^ | ||
if node.val == node.next.val: | ||
Line 13 in deleteDuplicates (Solution.py) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
ret = Solution().deleteDuplicates(param_1) | ||
Line 46 in _driver (Solution.py) | ||
_driver() | ||
Line 61 in <module> (Solution.py) | ||
``` | ||
headを参照しているnodeが属性valを持たないのは何故? | ||
ーー(73行目まで書いて気づいたが、これはnodeがNoneになっている、つまりもうnodeはないのにvalを求めてるせい。node is not Noneの条件を書けば良かった。) | ||
|
||
araiさんの動画を見た(https://www.youtube.com/watch?v=Y2gxc-p-KsI) | ||
最初にダミーのnodeを置くsentinel nodeというテクニックがあることを知った。 | ||
(https://ja.wikipedia.org/wiki/%E7%95%AA%E5%85%B5) | ||
sentinel nodeはデータの終了を示す特殊なデータのこと。 | ||
|
||
重複を見つけたら重複部分の終わり、つまり最後の重複のnextを前のノードを繋ぐ。 | ||
先頭に重複が来ることを想定してsentinel nodeを用意する。 | ||
|
||
olsen-blueさんのgitを読んでみた | ||
(https://github.com/olsen-blue/Arai60/pull/4) | ||
|
||
araiさんや他の人のgitを見るとdummyで書いていたが、sentinelは有名な呼び方じゃないのかな。 | ||
sentinelで書こうと思ったがdummyという変数名で書くことにする。 | ||
|
||
step2 | ||
```python | ||
class Solution: | ||
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
dummy = ListNode(0,head) | ||
last_non_duplicate_node = dummy | ||
node = head | ||
|
||
while node is not None and node.next is not 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. while 文の直後に空行を入れるのはあまり見ないかもしれません。好みの問題かもしれません。 |
||
if node.val == node.next.val and node.next is not None: | ||
while node.next is not None and node.val == node.next.val: | ||
node = node.next | ||
last_non_duplicate_node.next = node.next | ||
|
||
else: | ||
last_non_duplicate_node = last_non_duplicate_node.next | ||
|
||
node = node.next | ||
|
||
return dummy.next | ||
``` | ||
olsen-blueさんのコードを参考に書いた。 | ||
変数名だけ変更したが長すぎてあまり良くない | ||
|
||
whileやifの条件文を逆に書いたときエラーを吐いたので調べると短絡評価が原因っぽい。 | ||
andやorは必ずしも全て評価するわけではなく、以下のように評価していく。 | ||
orは短絡評価されます。つまり第一引数が偽のときにのみ、第二引数が評価されます。 | ||
andは短絡評価されます。つまり第一引数が真のときにのみ、第二引数が評価されます。 | ||
(https://docs.python.org/ja/3.10/library/stdtypes.html?highlight=set) | ||
|
||
以下はエラーが出た書き方。 | ||
```python | ||
if node.val == node.next.val and node.next is not None: | ||
while node.val == node.next.val and node.next is not None: | ||
node = node.next | ||
last_non_duplicate_node.next = node.next | ||
``` | ||
whileのところで引っかかったが、それはnodeがどんどん進んでいきnode.nextがNoneになったとき、while内で node.val == node.next.valを評価しようとしたため。 | ||
node.nextはNoneだからvalは持っていない。そのためエラーが起きた。 | ||
|
||
last_non_duplicate_nodeはやっぱり長すぎるのでlast_fixed_nodeにする。 | ||
|
||
step2-1 not accepted | ||
```python | ||
class Solution: | ||
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
dummy = ListNode(0,head) | ||
last_fixed_node = dummy | ||
node = head | ||
|
||
while node is not None and node.next is not None: | ||
|
||
if node.next is not None and node.val == node.next.val: | ||
while node.next is not None and node.val == node.next.val: | ||
node = node.next | ||
last_fixed_node = node.next | ||
|
||
else: | ||
last_fixed_node = last_fixed_node.next | ||
node = node.next | ||
return dummy.next | ||
``` | ||
106行目がlast_fixed_node.next = node.nextにできていなかった。 | ||
|
||
step3 | ||
1回目 2分39 | ||
2回目 失敗(last_fixed_node.next = node.nextのところをまた間違えた) | ||
|
||
1回目 2分28 | ||
2回目 2分21 | ||
3回目 2分 | ||
```python | ||
class Solution: | ||
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
dummy = ListNode(0,head) | ||
last_fixed_node = dummy | ||
node = head | ||
|
||
while node is not None and node.next is not None: | ||
|
||
if node.next is not None and node.val == node.next.val: | ||
while node.next is not None and node.val == node.next.val: | ||
node = node.next | ||
last_fixed_node.next = node.next | ||
|
||
else: | ||
last_fixed_node = last_fixed_node.next | ||
|
||
node = node.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. 関数内で空行を入れる際は 1 行のみとするのが良いと思います。 https://google.github.io/styleguide/pyguide.html#35-blank-lines
|
||
|
||
|
||
return dummy.next | ||
``` | ||
時間計算量はdummyと一緒に末尾まで進んでいるためO(2N) | ||
空間計算量はdummyも用意しているためO(2) | ||
|
||
レビューを受けて書き直したコードが以下 | ||
```python | ||
class Solution: | ||
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: | ||
dummy = ListNode(0,head) | ||
last_fixed_node = dummy | ||
node = head | ||
|
||
while node is not None and node.next is not None: | ||
if node.next is not None and node.val == node.next.val: | ||
while node.next is not None and node.val == node.next.val: | ||
node = node.next | ||
last_fixed_node.next = node.next | ||
|
||
else: | ||
last_fixed_node = last_fixed_node.next | ||
|
||
node = node.next | ||
return dummy.next | ||
``` |
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.xzxd7jwvkwc5