1.トピック
0、1、n-1のn個の数は、0から始まり、そのたびにこの円からm番目の数を削除して円に配置されます。円に残っている最後の番号を見つけます。
たとえば、0、1、2、3、4の5つの数字は円を形成します。0から3番目の数字を削除するたびに、削除される最初の4つの数字は2、0、4、1になります。最後に残りの数は3です。
例1:
输入: n = 5, m = 3
输出: 3
例2:
输入: n = 10, m = 17
输出: 2
制限:
- 1 <= n <= 10 ^ 5
- 1 <= m <= 10 ^ 6
二、解く
1.暴力的なシミュレーション(かろうじて合格)
アイデア:
現在の削除位置idx
、次の削除位置はidx + m
です。
ただし、現在の位置番号が削除されているため、次の番号が1つ前に移動するため、実際の次の位置はになりidx + m - 1
ます。数の終わりで、それは最初から数えられ、最後にモジュラスを取ります、それはそれ(idx + m - 1) % n
です。
添付:ArrayList.remove()コード
- LinkedList.remove()VS ArrayList.remove()
LinkedList
のremove()
時間計算量はO(n)O(n)です。O (n )、ArrayListと同じ。ただしArrayList
、連続コピーのメモリスペースは、LinkedList
多数の非連続アドレスアクセスと比較して、ArrayList
パフォーマンスは問題ありません。
コード:
class Solution {
public int lastRemaining(int n, int m) {
ArrayList<Integer> list = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
list.add(i);
}
int idx = 0;
while (n > 1) {
idx = (idx + m - 1) % n;
list.remove(idx);
n--;
}
return list.get(0);
}
}
時間計算量: O(n 2)O(n ^ 2)O (n2)
スペースの複雑さ: O(n)O(n)O (n )
2.数学的解決策
アイデア:
1.この問題は、数学的な解法を持つ有名なジョセフリング問題です。
全文キーリマインダー:最終的に生きている人のシリアル番号の変更のみに注意してください。
2.質問:各人に番号(インデックス値)を付け、各人を文字に置き換えます。
以下にN=8,m=3
例を示します。F(n, m)
最後に残った人のインデックス番号として表されるため、最後に残った人のインデックス番号の変更のみに注意してください
。8人から始めて、一度に1人ずつ殺します(位置はインデックスです)。殺された人(インデックス)を削除し、その人の次の最初の人(インデックス+ 1)から始めて、番号を付け直します。
- 初めてCが殺されたとき、人数は7人になり、Dが始まりでした(生き残ったGの数は6人から3人に変更されました)
- 2回目にFが殺されたとき、人数は6人になり、Gが始まりでした(生き残ったGの数は最終的に3から0に変わりました)
- 3回目にAが殺されたとき、人数は5人になり、Bが始まりでした(生き残ったGの数は最終的に0から3に変わりました)
- 類推すると、残りの人が1人だけの場合、彼の数は0でなければなりません。(強調)
3.最終的に生きている人の数が逆になります
Gのインデックス番号の変更プロセスを知ってから、プロセスをN = 7からN = 8に逆にします。
上記から、次のようになります。f(8、3)= [f(7、3)+ 3]%8 f(8、3)= [f(7、3)+3] \%8f (8 、3 )=[ f (7 、3 )+3 ] %8
一般化プロモーション、つまりf(n、m)= [f(n − 1、m)+ m]%mf(n、m)= [f(n-1、m)+ m] \ %mf (n 、m )=[ f (n−1 、m )+m ] %m
4.再帰式の導出
f(n、m)= {0 n = 0 [f(n − 1、m)+ m]%nn> 1 f(n、m)= \ left \ {\ begin {aligned} 0 && \ text {n = 0} \\ [f(n-1、m)+ m] \%n && \ text {n> 1} \ end {aligned} \ right。 f (n 、m )={{ 0[ f (n−1 、m )+M ] %のN n = 0 N> 1
より論理的な導出については、7-28孫悟空(20ポイント)を参照してください。より厳密な数学的導出については、ジョセフリング問題の漸化式の証明を参照してください。
コード:
class Solution {
public int lastRemaining(int n, int m) {
int ans = 0;
// 最后一轮剩下2个人,所以从2开始反推
for (int i = 2; i <= n; i++) {
ans = (ans + m) % i;
}
return ans;
}
}
時間計算量: O(n)O(n)O (n )
スペースの複雑さ: O(1)O(1)O (1 )
3、参照
1. Javaは、Josephリングの問題を解決し、シミュレーションがタイムアウトする理由を示します。
2.別の観点からの例でジョセフリングを解きます