Skip to content

solve: 141.Linked List Cycle#7

Open
t9a-dev wants to merge 2 commits intomainfrom
141.Linked-List-Cycle
Open

solve: 141.Linked List Cycle#7
t9a-dev wants to merge 2 commits intomainfrom
141.Linked-List-Cycle

Conversation

@t9a-dev
Copy link
Copy Markdown
Owner

@t9a-dev t9a-dev commented Oct 17, 2025

問題: 141. Linked List Cycle
次に解く問題: 142. Linked List Cycle II
ファイルの構成: ./src/bin/<各ステップ>.rs

return true;
}

slow_node = slow.borrow().next.as_ref().map(Rc::clone);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

うーん、こういうヘルパーを用意すると少しきれいになりますかね。

fn next_node(node: Option<Rc<RefCell<ListNode>>>) -> Option<Rc<RefCell<ListNode>>> {
    node.and_then(|n| n.borrow().next.clone())
}

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.

ありがとうございます。メソッドチェーンが長いなとは書いていて思ったのですが、言語仕様的に必要な呼び出しだから仕方ないかと違和感をスルーしていた部分でした。
ご指摘いただいてから改めて考えみると、ロジックに直接関係ない冗長な部分をヘルパーに切り出すのは納得できる理由だと思いました。
だいぶすっきり書けるなと思いました。

pub fn has_cycle(head: Option<Rc<RefCell<ListNode>>>) -> bool {
    let (mut slow_node, mut fast_node) = {
        let current = head.as_ref().map(Rc::clone);
        let next = Self::next_node(head);

        (current, next)
    };

    while let (Some(slow), Some(fast)) = (slow_node, fast_node) {
        if Rc::ptr_eq(&slow, &fast) {
            return true;
        }

        slow_node = Self::next_node(Some(slow));
        fast_node = Self::next_node(Self::next_node(Some(fast)));
    }

    false
}

fn next_node(node: Option<Rc<RefCell<ListNode>>>) -> Option<Rc<RefCell<ListNode>>> {
    node.and_then(|n| n.borrow().next.as_ref().map(Rc::clone))
}


改善する時に考えたこと
-
- 変数名について単にnodeとしていた箇所を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.

変数名ですがnodeのままでもいいかなと思います。
current_nodeだとcurrentと対になるようなノード(previous, nextなど)があるかもしれないという連想が働くので、ちょっとだけ読み手のコストが増す気がします。
Zun-U/coding-practice-mochi0123#2 (comment)

Copy link
Copy Markdown

@naoto-iwase naoto-iwase left a comment

Choose a reason for hiding this comment

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

お疲れさまです。

LeetCodeにRust実装がなかったとのことで、大変だったと思います。丁寧に実装を考えられているという印象を持ちました。

1点だけコメントさせていただきました。

Comment on lines +40 to +42
pub struct ListNode {
pub next: Option<Rc<RefCell<ListNode>>>,
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Option<Rc<RefCell<ListNode>>>がボイラープレートっぽいので、型エイリアスを使うのはどうでしょうか。

Suggested change
pub struct ListNode {
pub next: Option<Rc<RefCell<ListNode>>>,
}
type Link = Option<Rc<RefCell<ListNode>>>;
pub struct ListNode {
next: Link,
}

テストとか書くときも少し気が楽になるかもです。

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.

ありがとうございます。型エイリアスは活用したことがなく提案いただくまで選択肢にもなかったので、すごく勉強になりました。(アハ体験でした。)

impl Solution {
pub fn has_cycle(head: Option<Rc<RefCell<ListNode>>>) -> bool {
let mut visited_node: HashSet<_> = HashSet::new();
let mut next_node = head;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

レビューが遅くなり、申し訳ありません。
next_nodeの命名がなるほど、と思った反面、「next」という単語の意味に「現時点から次」と連想してしまう場合もあると思いますので、target_nodeにする案はどうでしょうか。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants