1. トピックの説明と要件
80. ソートされた配列の重複を削除 II - LeetCode
トピックの説明
順序付けされた配列 nums を指定すると、 2 回以上出現する要素が 2 回のみ出現するように、繰り返される要素を所定の位置で削除し、削除された配列の新しい長さを返してください。
余分な配列スペースを使用しないでください。入力配列をインプレースで変更し、O(1) の追加スペースを使用して変更する必要があります。
例
例 1:
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。
例 2:
输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7, nums = [0,0,1,1,2,3,3]
解释:函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 不需要考虑数组中超出新长度后面的元素。
ヒント
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums
昇順にソート
2. 問題解決のアイデア
一般的なアイデア:
最初にトピックを分析します。このトピックでは、順序付けされた配列を指定すると、配列内に 2 回以上出現する要素を削除する必要があり、変更できるのは元の配列のみであり、追加の配列を借用することはできないと述べています。配列の新しい長さ。
まず、配列内で 2 回以上出現する要素を削除したいのですが、次に配列全体を走査する必要がありますが、2 回以上出現する要素を見つけて削除するにはどうすればよいでしょうか。最も単純なアイデアは、各要素を後続の要素と順番に比較し、回数を数え、比較中に出現回数が 2 を超えた場合に変更することですが、この実装方法ではネストされたループを使用する必要があり、空間の複雑さは比較的高く、実装がより複雑です。したがって、「ダブル ポインター」方法、つまり 2 つのポインターを使用して配列要素を走査して更新する方法を考えることができます。したがって、2 つの変数を定義できます。1 つは配列の走査に使用され、もう 1 つは更新された配列の長さの記録と配列の更新に使用されます。
では、配列の様子を解析してみましょう 配列の要素数が 2 以下の場合は、配列の長さを直接返すことができます。各要素が 2 回のみ出現することを確認する必要があるため、最初の要素と 3 番目の要素を比較する必要があります (タイトルに順序付けされた配列と記載されているため)。それらが等しい場合、それは現在の要素の出現回数を意味します。これは 2 より大きいため、トラバーサル ポインターは後方に移動し、前の要素と等しくない要素を見つけて割り当て、変更された配列の長さを更新します (つまり、更新ポインターは 1 ビット後方に移動します)。 。したがって、2 つのポインターの初期値は 2 であり、各比較は、トラバーサル ポインターが指す要素と、更新ポインターが指す要素の前の 2 番目の要素 (右から左から 2 番目) を比較することによって行われます。 。
[以下は2つのポインタの変化を解析する例です]
具体的な手順:
①配列の長さが2より大きいかどうかを判定する
② 2つのポインタを初期化する
③配列を走査して更新する
④更新された配列長を返す
3. 具体的なコード【C言語】
int removeDuplicates(int* nums, int numsSize){
if(numsSize<=2) return numsSize;
int left = 2, right = 2;//有序数组,每个元素只出现两次,因此right从下标2开始遍历
//while的执行条件为right<numsSize,即未遍历完数组
while (right < numsSize) {
//比较当前位置的元素与自己前面第二个元素是否相等
//如果相等则需要继续向后面找新的元素替代掉当前位置的元素
//如果不相等则将此时right所指向的元素赋值给left所指向的元素
//left就是修改后的数组长度,而right是用来遍历访问整个数组的
if (nums[left - 2] != nums[right]) {
nums[left] = nums[right];
++left;
}
++right;
}
return left;
}