目次
1. トピック分析
トピックリンク: 1089. ゼロの上書き - Leetcode
まずはタイトルを読んでいきますが、
タイトルの意味は実はとてもシンプルで、
0 が見つかった場合は、1 つをコピーして配列に書き込み、右側の要素を 1 ビット右にシフトします。
例題を見ると質問の意味が理解しやすいです。
2. アルゴリズム原理
一般に、配列の要素を移動する必要があるような質問は、
ダブル ポインター演算も、問題を解決するために非常によく使用されます。
この質問がインプレース アルゴリズムを使用しない場合、質問は非常に単純になります。
元の配列をトラバースするポインタ、新しい配列をトラバースするポインタ、
非ゼロに遭遇した場合は、それを配列に直接書き込み、0 に遭遇した場合は配列に 2 つの 0 を書き込みます。
このアルゴリズムをインプレースで最適化したい場合はどうすればよいでしょうか?
左から右に試してみましょう。
うまくいきそうにありません:
元の数値が変更されているため、すべてが 0 にコピーされる状況が発生します。
次に、後ろから前に向かって考えてみましょう。
cur が最後の書き込みの場所を指すようにします。
次に、ダブル ポインターのプロセスをシミュレートします。
cur が 0 に遭遇すると、2 回コピーされます。
非ゼロに遭遇した場合は通常どおりに書き込みます。
等々:
私たちは成功したことがわかりました、
ここで問題は、cur の開始位置をどのように取得するかです。
あるいは、最後の書き込みの場所を取得するにはどうすればよいでしょうか?
2 つのポインター cur と dest を使用して、ダブル ポインターを再度記述するプロセスをシミュレートできます。
1. 現在の位置が 0 であるか非ゼロであるかを判断します。
2. dest は、cur 位置の値に従って 1 歩または 2 歩進むことを決定します。
3. destが最後に到達したかどうかを確認します
4. 末尾に到達していない場合は cur++、末尾に到達している場合は、cur が指す位置が最後に書き込まれた番号になります。
ただし、dest の範囲外の問題に注意してください。最後から 2 番目の番号に達したときに cur が 0 になった場合、
destが2歩後退すると、境界を越えるという問題が発生します。時間が来たら、cur は 1 歩下がり、dest は 2 歩下がります。
3. コードの書き方
class Solution {
public:
void duplicateZeros(vector<int>& arr) {
int dest = -1, cur = 0, size = arr.size();
// 找到最后一次写入的位置
while(cur < size) {
if(arr[cur]) dest++;
else dest += 2;
if(dest >= size - 1) break; //走完了
cur++;
}
// 控制边界
if(dest == size) { //这种就是最后一步是0,走了两步dest越界的情况
arr[size - 1] = 0;
dest -= 2;
cur--;
}
// 从后往前做写入操作
while(cur >= 0) {
if(arr[cur]) arr[dest--] = arr[cur--];
else {
arr[dest--] = 0;
arr[dest--] = 0;
cur--;
}
}
}
};
最後に次のように書きます。
以上が今回の記事の内容となります、読んでいただきありがとうございます。
何かを得たと感じたら、ブロガーに「いいね! 」を与えることができます。
記事の内容に抜けや間違いがある場合は、ブロガーにプライベートメッセージを送信するか、コメントエリアで指摘してください〜