Skip to content

83. Remove Duplicate from Sorted List #5

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
90 changes: 90 additions & 0 deletions lc83.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
"""test1
case1とcase2は小さい順に並んでいるケースだけど、問題文に返り値のリストはソートされてないといけないと言うことは、適当に数字が格納されているケースまで想定しなければならないってことだよね。
データ構造を考えたけど、set()でやれば終わりじゃ無いか?
set()でやったときの計算量を概算したいけどどうやって削除しているのかを理解してないので答えられない。step2で調べます。
これは削除じゃなくて前から見て行ってあったら追加しない、なかったら追加と言う方法になるのか。ただその場合は、結局全部見ることになるので時間計算量はO(n)になりそう?

[1, 2]がListNodeの型じゃ無いって言われた。その通りだけどどう解こう。これは変数=ListNode()をすれば良いね。

結局30分を経過したので解けなかったが、最終的な方針としては以下のようにやった。
1. while文でリストに重複していないものを格納してからsorted()で整列。
2. ListNodeオブジェクトを生成し1で作成したリストをもとに格納していく。ここでは.valに1で作成したリストの要素を格納。nextには次の要素を格納していく。

ここで詰まったことは、主に二つ。一つ目は、与えられた数字の最後のみが格納されているListNodeオブジェクトが生成されてしまう。これはnextの扱い方がよくわからなかったため。二つ目は、以下のエラー文の通り。

AttributeError: 'int' object has no attribute 'val'
^^^^^^^^^^^^^^^^^^^^
non_overlap_node.val = non_overlap_node_list[i]

なんでこうなるのかよくわからん。

変数名に関しては、長くなっていることは理解した上でnon_overlap_nodeを最初につけている。
ただし、これが可読性のある変数名であるかは客観的に判断しかねるのでコードレビューをされる方には、ぜひ意見をお伺いしたい。
30分
"""
non_overlap_node_list = list()
Copy link

Choose a reason for hiding this comment

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

コピペにミスがあり、関数定義のdefの行が抜けていたり、インデントがずれていそうです。

node = head

while node:
if node.val not in non_overlap_node_list:
non_overlap_node_list.append(node.val)

node = node.next

non_overlap_node_length = len(non_overlap_node_list)
non_overlap_node_list = sorted(non_overlap_node_list)
non_overlap_node = ListNode()
Copy link

Choose a reason for hiding this comment

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

step2以降はかなりスッキリしていますが、変数名がやや冗長に見えました。
変数名に関するレビューの下記も参考にしていただけると良いかと思います。
https://discord.com/channels/1084280443945353267/1230079550923341835/1230201155619913728

Copy link
Owner Author

Choose a reason for hiding this comment

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

気づいていませんでした、以降気をつけます!


for i in range(non_overlap_node_length):
Copy link

Choose a reason for hiding this comment

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

私は、len(array) は変数にしないほうが、いいかもなあと思います。

for i in range(len(array)):

と書かれていたら array の添字を舐めていることがわりとはっきりしてますよね。

あと、リストの構築で端の処理は、場合分けをしてもいいんですが、頭を場合分けをするか尻尾を場合分けするかの二つのオプションがあります。また、番兵といって、頭と尻尾に特殊なノードを加えて後で除くことで、ループ内はきれいにするという作戦もあります。

non_overlap_node.val = non_overlap_node_list[i]

if i == non_overlap_node_length-1:
non_over_lap_node.next = None
else:
non_overlap_node.next = non_overlap_node_list[i+1]

non_overlap_node = non_overlap_node.next

return non_overlap_node

"""step2
なんかそもそもListNode、連結リストの概念を間違えて理解していたっぽいのでstep1は的外れな解答をしていることがわかった。
あとは142でもそうだったけど問題文が読めていなさすぎる、、、sorted listが与えられているからソートしているかを判別するかとかは今回の問題だとどうでも良い。
仕組みを理解すればどうってことない問題だった(1分30秒)。一つ気になるのはnode_valという変数だけど、これは読みやすいのか? node_valとnode.valで混同しそう。https://discord.com/channels/1084280443945353267/1225849404037009609/1234206158630289450 にcurrentを変数名につけるときのことについて書いてあるんだけど(前回指摘された)何か最適なのはあるのだろうか。
"""
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None:
return head

node = head
node_val = head.val

while node and node.next:
if node.next.val == node_val:
Copy link

Choose a reason for hiding this comment

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

node_valは使わなくても良さそうです。

class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None:
            return head

        node = head

        while node and node.next:
            if node.next.val == node.val:
                node.next = node.next.next
            else:
                node = node.next

        return head

Copy link

Choose a reason for hiding this comment

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

さらに私の書いた上記のコードからelseを除いて、その下の行のインデントを一つ上げられますね。

Copy link
Owner Author

Choose a reason for hiding this comment

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

node_valは必要なさそうですね、ありがとうございます

node.next = node.next.next
else:
node = node.next
node_val = node.val

return head

"""step3
1分30分
"""
class Solution:
Copy link

Choose a reason for hiding this comment

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

再帰で解いたりしている方もいるので、参考になるかもしれません。
https://github.com/goto-untrapped/Arai60/pull/42/files

Copy link
Owner Author

Choose a reason for hiding this comment

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

step4の別解としてみてみます、ありがとうございます

def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if head is None:
return head

node = head
node_val = node.val

while node and node.next:
if node.next.val == node.val:

Choose a reason for hiding this comment

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

val が重複している間は次の node をスキップし続けるやり方もできそうです。
例えば ↓ をイメージしました。

def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
    node = head
    while node:
        while node.next is not None and node.val == node.next.val:
            node.next = node.next.next
        node = node.next
    return head

node.next = node.next.next
else:
node = node.next
node_val = node.val

return head