-
Notifications
You must be signed in to change notification settings - Fork 0
Create RemoveDuplicatesfromSortedList.md #3
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
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,124 @@ | ||
| # step1 何も見ずに解く | ||
|
|
||
| ## 解答 | ||
| - Set使わなくても書けるはずだが、パッと思いついたのでSetを使って実装 | ||
| - 意図は理解しやすい気はするが、流石に無駄が多いか | ||
| - 計算量 | ||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(n) | ||
| - これって2回ループ回しているからO(2n)とすべきですか? | ||
| ```java | ||
| /** | ||
| * Definition for singly-linked list. | ||
| * public class ListNode { | ||
| * int val; | ||
| * ListNode next; | ||
| * ListNode() {} | ||
| * ListNode(int val) { this.val = val; } | ||
| * ListNode(int val, ListNode next) { this.val = val; this.next = next; } | ||
| * } | ||
| */ | ||
| class Solution { | ||
| public ListNode deleteDuplicates(ListNode head) { | ||
| if (head == null) { | ||
| return null; | ||
| } | ||
|
|
||
| // 重複を省いたvalの配列を作成 | ||
| ListNode node = head; | ||
| HashSet<Integer> uniqueValManager = new HashSet<>(); | ||
|
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. Managerという名前は何か管理するための機能を持ったクラスのような印象を受けるので、ここでは少し大げさかなと思いました。 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. 単にvisitedとかseenとかでもいいと思います。
Owner
Author
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. ユニークな値を管理するというニュアンスで名付けましたが、変に説明的にし過ぎるより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. unique な値を管理するよというのは HashSet を使う時点で自明なので、visited や seen などの用途に着目したシンプルな名前で十分かなと思います。
https://docs.oracle.com/javase/8/docs/api/java/util/Set.html |
||
| ArrayList<Integer> uniqueVals = new ArrayList<>(); | ||
|
Comment on lines
+29
to
+30
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. new_head と new_node を定義すれば、このあたりの変数はまるっと消せそうな感じがします。
Owner
Author
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. 最初に思い浮かんだのがSetを利用した実装でしたが、Set使わなくても実装できます。 |
||
| while (node != null) { | ||
| if (!uniqueValManager.contains(node.val)) { | ||
| uniqueValManager.add(node.val); | ||
| uniqueVals.add(node.val); | ||
| } | ||
| node = node.next; | ||
| } | ||
|
|
||
| // valの配列を元に繋ぎ直す | ||
| ListNode prevNode = head; | ||
|
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. 「前のノード」というのは書き手の視点から見た名前で、これは実際には「重複を排除した新しい連結リスト」を作っていっているのでそのことが分かる名前にされていると読み手にとって分かりやすいかなと思いました。
Owner
Author
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. 新しいLinked listの末尾を指すのでnewTailなどとするのが分かりやすいでしょうか。ありがとうございます! |
||
| prevNode.next = null; | ||
| // 配列の先頭の値は追加不要なので 1 からスタート | ||
| for (int i = 1; i < uniqueVals.size(); i++) { | ||
| prevNode.next = new ListNode(uniqueVals.get(i)); | ||
| prevNode = prevNode.next; | ||
| } | ||
| return head; | ||
|
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. 最初の head だけ既存のものを使い、それ以降は新しい node をつなげているのって何か理由があるのでしょうか? headも含め、完全に新しい LinkedList として作成する方が自然な気がします。
Owner
Author
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. headを再利用することで重複削除後のLinkedListの先頭を保持する変数の宣言を省きたかったからだと思います。 |
||
| } | ||
| } | ||
| ``` | ||
|
|
||
| # step2 他の方の解答を見る | ||
|
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. 参考にした人のリンクとかを貼っておくと、後で見返すときに便利かなと思います。
Owner
Author
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. 確かにその方が便利ですね。 |
||
| 当初書こうとした時はprevNode保持してとか考えたが、`node.next.next`使えばよかった | ||
| ## 解答 | ||
| - 1重ループ版 | ||
| - 計算量 | ||
| - 時間計算量: O(n) | ||
| - 空間計算量: O(1) | ||
| - `continue`で書くか、`if-else`で書くか悩む | ||
| - `continue;`を使い、`while`ループの末尾で必ず`node`を更新する方が事故が起こりづらそう | ||
| ```java | ||
| class Solution { | ||
| public ListNode deleteDuplicates(ListNode head) { | ||
| if (head == null) { | ||
| return null; | ||
| } | ||
|
|
||
| ListNode node = head; | ||
| while (node != null && node.next != null) { | ||
|
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. ループの中でnodeがnullになることがないので、 |
||
| if (node.val == node.next.val) { | ||
| node.next = node.next.next; | ||
| continue; | ||
| } | ||
| node = node.next; | ||
| } | ||
| return head; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## 解答2 | ||
| - 2重ループ版 | ||
| ```java | ||
| class Solution { | ||
| public ListNode deleteDuplicates(ListNode head) { | ||
| if (head == null) { | ||
| return null; | ||
| } | ||
|
|
||
| ListNode node = head; | ||
| while (node != null) { | ||
| // valが重複するならnextを上書き | ||
| while (node.next != null && node.val == node.next.val) { | ||
| node.next = node.next.next; | ||
| } | ||
| node = node.next; | ||
| } | ||
| return head; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| # step3 3回ミスなく書く | ||
| - 1重ループの方が好みなのでそちらで実装。 | ||
| ## 解答 | ||
| ```java | ||
| class Solution { | ||
| public ListNode deleteDuplicates(ListNode head) { | ||
| if (head == null) { | ||
| return null; | ||
| } | ||
|
|
||
| ListNode node = head; | ||
| while (node != null && node.next != null) { | ||
|
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. nodeがnullになるより前に先にnode.nextがnullになるので 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. https://github.com/kt-from-j/leetcode/pull/3/files#r2342761571 nanae772さんのコメントも確かにと思う一方、個人的には冗長な条件式はない方が良い気持ちですね…
Owner
Author
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.val == node.next.val) { | ||
| node.next = node.next.next; | ||
| continue; | ||
| } | ||
| node = node.next; | ||
| } | ||
| return head; | ||
| } | ||
| } | ||
| ``` | ||
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.
Big-O記法では定数倍は無視されるためO(n)と書くのが一般的だと思います
https://ja.wikipedia.org/wiki/%E3%83%A9%E3%83%B3%E3%83%80%E3%82%A6%E3%81%AE%E8%A8%98%E5%8F%B7
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.
定数倍として無視ですよね。
今回改めて考えてBig-O記法って極限での振る舞いを考えるものであるため、nが小さい場合には大雑把過ぎるということが腹落ちしました。