【リンクリスト問題】ジョセフの循環単一リンクリスト問題

序文

特別なトピックの形でブラッシングの投稿を更新します。私と一緒にブラッシングを学ぶことを歓迎します。私を信じてください。あなたの粘り強さは間違いなく予想外の利益をもたらします。それぞれの質問は簡単な答えを提供します、あなたがよりエレガントなアプローチを持っているなら、ガイダンスを提供することを歓迎します、ありがとう

【トピック説明】

【リンクリスト問題】ジョセフの循環単一リンクリスト問題

【請求】

入力:循環単一リンクリストのヘッドノードと報告された数m。

戻り値:最後に残ったノード。このノードはそれ自体で循環単一リンクリストを形成し、他のすべてのノードは削除されます。

【困難】

タクシー:★☆☆☆

【回答】

方法1:時間の複雑さはO(n * m)です

時間の複雑さを考慮しなければ、この問題は非常に単純です。循環リンクリストをトラバースし、m個のノードをトラバースするたびにノードを削除します。リンクリストに残っているノードは1つだけであることを知っていれば十分です。

コードは以下のように表示されます

 1    //时间复杂度为O(n*m)的解决方法
 2    public static Node josephusKill(Node head, int m) {
 3        if(head == null || m < 1)
 4            return head;
 5        Node last = head;
 6        //定位到最后一个节点
 7        while (head.next != last) {
 8            head = head.next;
 9        }
10        int count = 0;
11        while (head.next != head) {
12            if (++count == m) {
13                head.next = head.next.next;
14                count = 0;
15            } else {
16                head = head.next;
17            }
18        }
19        return head;
20    }

一部の携帯電話では文字が文字化けしている可能性があるため、ここに写真を投稿します。

【リンクリスト問題】ジョセフの循環単一リンクリスト問題
このメソッドの時間の複雑さはO(n * m)です。時間の複雑さは、以下の解決策として使用されます。

方法2:時間の複雑さはO(n)です

この方法の難しさは次のとおりです。

学校:★★★☆

循環リンクリストのノードに番号を付けることができます。リンクリストのノード数がnの場合、ヘッドノードから始めて、ノードに順番に番号を付けます。つまり、ヘッドノードは1、次のノードは2、最後のノードはnです。

f(n)を使用して、循環リンクリストの長さがnの場合、生存者の数はf(n)であることを示します。明らかに、n = 1の場合、f(n)= 1です。f(n)とf(n-1)の関係がわかれば、再帰的に解くことができます。人数はn人、mに報告した人は自殺すると仮定します。その場合、最初の番号は

m-2

m-1

m

m + 1

m + 2

1回削除すると、mという番号のノードが削除されます。削除後、残っているノードはn-1個だけです。削除前後の数値変換関係は次のとおりです。

削除する前---削除した後

…---…

m-2 --- n-2

m-1 --- n-1

m ----なし(番号が削除されているため)

m + 1 --- 1(次回はここから数えるため)

m + 2 ---- 2

…----…

新しいリングにはn-1個のノードしかありません。そして、m + 1、m + 2、m + 3の番号が付けられたノードは、新しいリングで1、2、3の番号が付けられたノードになります。

oldが削除前のノード番号、newがノード削除後の番号であるとすると、oldとnewの関係はold =(new + m-1)%n +1です。

注:なぜ古いものではないのか疑問に思う人もいるかもしれません=(新しい+ m)%n?主な理由は、番号付けが0からではなく1から始まるためです。new + m == nの場合、最終的な計算結果はold = 0になります。とても古い=(新しい+ m-1)%n +1。

このようにして、f(n)とf(n-1)の間の関係、およびf(1)= 1を取得します。したがって、再帰的な方法でそれを行うことができます。

コードは次のように表示されます。

 1   //时间复杂度为O(n)
 2    public static Node josephusKill2(Node head, int m) {
 3        if(head == null || m < 1)
 4            return head;
 5        int n = 1;//统计一共有多少个节点
 6        Node last = head;
 7        while (last.next != head) {
 8            n++;
 9            last = last.next;
10        }
11        //直接用递归算出目的编号
12        int des = f(n, m);
13        //把目的节点取出来
14        while (--des != 0) {
15            head = head.next;
16        }
17        head.next = head;
18        return head;
19    }
20
21    private static int f(int n, int m) {
22        if (n == 1) {
23            return 1;
24        }
25        return (f(n - 1, m) + m - 1) % n + 1;
26    }

画像コード:

【リンクリスト問題】ジョセフの循環単一リンクリスト問題

問題の拡大

前の質問で、K番目のノードから番号を削除するとしますか?それを解決する方法は?

回答

舞台裏の返信回答3回答を得る

過去

【リンクリストの問題】単一リンクリストの中間ノードを削除する

[リンクリストの問題]単一リンクリストをエレガントに反転する方法

[リンクリストの問題]単一リンクリストのK番目のノードを削除します

[アルゴリズムの戦闘]ウィンドウの最大値の配列を生成する
【リンクリスト問題】ジョセフの循環単一リンクリスト問題

おすすめ

転載: blog.51cto.com/15015171/2555344