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
133 changes: 133 additions & 0 deletions md/2-09_MiddleoftheLinkedList.md
Copy link

@Kitaken0107 Kitaken0107 Jul 21, 2024

Choose a reason for hiding this comment

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

1st:
個人的には、関数にすると登場人物多くなるのと今回複数同じ処理をするわけではないので、
関数にしない方がスッキリ書ける気がします
・for文でnodeを最後まで進める+node数カウンターを用意する
・node数の半分になるようなカウンター(A)を用意して代入
・while文でAを一つずつ減らしながら、0になるまで進める

Choose a reason for hiding this comment

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

2nd:
LinkedListの構造うまく使っていて勉強になりました、、

Copy link

Choose a reason for hiding this comment

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

関数にするいいところは、変数のスコープが限定できるところです。後は程度問題ですね。
https://discord.com/channels/1084280443945353267/1201211204547383386/1215702126945112094

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます.関数にしない方法も試してみます

Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# 2-09_MiddleoftheLinkedList
Author: WaveAlchemist
Given the head of a singly linked list, return the middle node of the linked list.

If there are two middle nodes, return the second middle node.

# 1st
初見では以下の方針で解答
- nodeを最後まで(Noneになるまで)進める
- 最後まで進んだらその時何番目か(node_count)を返す
- int(node_count / 2 + 1)番目まで最初からnodeを進める
- nodeの数を計算する関数と希望するnode数nodeを進める関数を作成
解答時間は12min39sでした
思いついたアルゴリズムがこれだけだったのでこれで提出しましたが,無駄なことをやっているような気がしています.
Copy link

Choose a reason for hiding this comment

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

私はこれが標準的な解答でいいと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます.


``` Python
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
def checkNodeNumber(node, node_count):

Choose a reason for hiding this comment

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

node_countを外から与えているのが気になりました。
これは、headを与えるとtailまでのノード数を計測して返す関数、ですよね。
となるとnode_countの初期値は常に1なので関数内で定義するのが良いのかなと(なんか読み違えていたらすみません)

Copy link
Owner Author

Choose a reason for hiding this comment

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

ご指摘の通りかと思います.
純粋に

def checkNodeNumber(node):
            node_count = 1 # 1-indexed
            while node.next:
                node = node.next
                node_count += 1
            return node_count

で良いですね(いちいち外部からnode_countを与えるのはくどいですね(笑))

Choose a reason for hiding this comment

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

Function names should be lowercase, with words separated by underscores as necessary to improve readability.

leetcode側の表記がアレですが、合わせなくても良いかと。

ご参考:
https://peps.python.org/pep-0008/#function-and-variable-names

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます
PEP8の読み込みが甘かったです

while node.next:
node = node.next
node_count += 1
return node_count
def proceedNode(node, end_node):

Choose a reason for hiding this comment

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

end_nodeという名前ですが、実態はheadから数えた目的のnodeまでのnode数のようです。
num_proceedとかどうでしょう(ただその場合はmax_node_count-1を入れる必要があるのに注意です)

もっというと、checkNodeNumberで計算するものを進めるnode数にすれば、整理されるかと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

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

ありがとうございます.headから目的のnodeまで進めるという関数という意図ですので,
num_proceedがいいですね.

check_node_numberはnodeの数という意図ですので,この関数で進めるnode数を計算するのであれば関数名は変更したほうがいいですね.check_middle_node_numberとかどうでしょうか?

node_count = 1
Copy link

Choose a reason for hiding this comment

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

好みの問題かもしれませんが、countが1から始まるのは少し違和感あるかもしれません。(1-indexedとしているの場合、コメントがあると嬉しいかもです。)

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の個数という意図でしたので1-indexedです.つまり, head = [3] ならnodeは1つと数えた方が感覚的には理解しやすいかと.
ただおっしゃる通り確かにpythonは0-indexedなのでミスリーディングかもしれません・・
コメントで# 1-indexedという注意書きをしておきます.

while node.next and node_count:

Choose a reason for hiding this comment

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

node_countの条件が機能してないように見えます。
ここに入れるなら、whileの中でnodeを進めるごとにnode_countを1つずつ減らしていくような実装はできると思います。

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_countを減らしていくという発想はなかったです.ありがとうございます
以下の修正いかがでしょう

def proceed_node(node, num_proceed):
            while node.next:
                node = node.next
                num_proceed -= 1 
                if num_proceed == 0:
                    return node
            return node

node = node.next
node_count += 1
if node_count == end_node:
return node
return node
max_node_count = checkNodeNumber(head, 1)
middle_node_count = int(max_node_count / 2 + 1)
Copy link

Choose a reason for hiding this comment

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

自分だったら、型変換を避けるため、(max_node_count // 2) + 1と書きます。

Copy link
Owner Author

Choose a reason for hiding this comment

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

返答遅くなり申し訳ございません!
ご指摘ありがとうございます.

return proceedNode(head, middle_node_count)
```

# 2nd
LeetCodeのSolutionsを参照
Linked List Cycleで出てきたfastとslowを用いる方法を実装
fast.nextがNoneになった時点でfastはmiddle nodeにいるということに留意

Choose a reason for hiding this comment

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

確かにこの方法がありましたね。
LinkedListの問題に特化して理解していました(反省)

Copy link
Owner Author

Choose a reason for hiding this comment

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

私も自力では思いつきませんでした・・・
ほかの問題で出てきた考え方を応用できるといいですよね!


``` Python
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
slow = fast = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
return slow
```

# 3rd
レビューのコメントをもとに再度構築しました(解法は1stのものをベースにしています)

- int(max_node_count / 2 + 1) -> max_node_count // 2 + 1
- node_count = 1に1-indexedというコメントを付与
- checkNodeNumber -> check_node_number, proceedNode -> proceed_node
- proceed_node内部でnodeを進めるごとにnum_proceedを1ずつ減らすという方法を実装

check_node_numberでnodeの数を数える場合

```Python
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
def check_node_number(node):
node_count = 1 # 1-indexed
while node.next:
node = node.next
node_count += 1
return node_count

def proceed_node(node, num_proceed):
while node.next:
node = node.next
num_proceed -= 1
if num_proceed == 0:
return node
return node

max_node_count = check_node_number(head)
middle_node_count = max_node_count // 2 + 1
return proceed_node(head, middle_node_count - 1)

```

check_node_numberをcheck_middle_node_numberとし,進めるべきnode数(つまり真ん中のnode数)を計算する場合
return node_count // 2として,proceed_nodeに代入するのはmiddle_node_countでいいのかも
(ただ,関数の名前的にはノードの数ということになるので,感覚としては現状がいい気もする。
つまり,真ん中のノードの数とノードを進める回数は違うということ)

``` Python
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
def check_middle_node_number(node):
node_count = 1 # 1-indexed
while node.next:
node = node.next
node_count += 1
return node_count // 2 + 1

def proceed_node(node, num_proceed):
while node.next:
node = node.next
num_proceed -= 1
if num_proceed == 0:
return node
return node

middle_node_count = check_middle_node_number(head)
print(middle_node_count)
return proceed_node(head, middle_node_count - 1)
```

関数を使わない方法も試してみる
思ったよりスッキリかけた気がします.nodeを進めるときのwhile文はfor文で書いてもいいかもしれません.

``` Python
class Solution:
def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
node = head
node_count = 1 # 1-indexed
# check node number
while node.next:
node = node.next
node_count += 1
# check node number to be proceeded
num_proceed = node_count // 2
# proceed node
node = head
for proceed in range(num_proceed, 0, -1):
node = node.next
return node
```