タイトル説明:
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
問題解決のアイデア:
法律に従って結果が逆になりました(leetcodeから盗まれた写真):
まず、上の写真のプロセスを理解する必要があります。つまり、各サイクルでのより安全な位置です。
削除された番号(キー)の移動位置がわかりますか
- それは図から描くことができます:数字を削除した後、数字の文字列全体が2つの部分に分割され、後者は前に配置され(3桁左に移動)、前の補数は後ろにあります、
この時点で削除された場合最後に再追加された番号は元の配列ですが、2つの部分の位置が変更されています。 - したがって、この時点でシーケンスが与えられた場合、前のシーケンスを逆にすることはできますか?
つまり、最後に1桁を構成し、シーケンス全体が3桁右に移動すると、次の数桁がオーバーフローします。 、だからもう一度前回の長さを割ります。その後、オーバーフローした人は戻って、削除前の状態に戻ります。 - したがって、特定の位置に移動すると、最後の位置は「(この位置+間隔の長さ)%前回の長さ」ではなく、最後の位置になります。
つまり、今回は位置を右に3桁移動します。オーバーフローがない場合は、前回が遅れていることを意味します。オーバーフローしている場合は、前回が先頭にあることを意味します。最後の削除後、後ろに移動したので、長さで割ると元の位置に戻ります。
これから、逆控除のプロセス検証が得られます。
- 1-> 2のプロセス:(0 + 3)%2 = 1の位置
- 2-> 3のプロセス、つまり(1 + 3)%3 = 1の位置
- 3-> 4のプロセス、つまり(1 + 3)%4 = 0の位置
したがって、このコードは非常に単純ですが、理解するのは少し難しいです。
コード:
class Solution {
public:
int lastRemaining(int n, int m) {
int q=0;
for(int i=2;i<=n;i++)
{
q=(q+m)%i;
}
return q;
}
};