ソートされた配列内の重複を削除する
昇順の配列を指定した場合nums
、各要素が 1 回だけ表示されるように、繰り返される要素を所定の位置で削除し、削除された配列の新しい長さを返してください。要素の相対的な順序は一貫している必要があります。次に、nums
内の。
nums
一意の要素の数が であることを考慮するとk
、ソリューションが確実に合格するには次のことを行う必要があります。
- の最初の要素に、最初にに出現よう
nums
に配列を変更します。およびのサイズは重要ではありません。nums
k
nums
nums
nums
- 返品
k
。
判断基準:
システムは次のコードを使用してソリューションをテストします。
int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案
int k = removeDuplicates(nums); // 调用
assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
assert nums[i] == expectedNums[i];
}
すべてのアサーションが合格すれば、ソリューションは合格します。
例 1:
入力: nums = [1,1,2]
出力: 2、nums = [1,2,_]
説明: 関数は新しい長さ 2 を返す必要があり、元の配列 nums の最初の 2 つの要素は 1 に変更されます。 、2.配列内の新しい長さを超える要素は考慮する必要はありません。
例 2:
入力: nums = [0,0,1,1,1,2,2,3,3,4]
出力: 5、nums = [0,1,2,3,4]
説明: 関数は新しい値を返す必要があります。長さは 5 で、元の配列 nums の最初の 5 つの要素は 0、1、2、3、4 に変更されます。配列内の新しい長さを超える要素は考慮する必要はありません。
ヒント:
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums は昇順にソートされます。
これは 1 つです双指针问题
。この問題を解決するには、スロー ポインター ji
と。低速ポインタは、現在の非反復要素の最後の位置を指すi
ために使用され、高速ポインタはj
配列を走査するために使用されます。走査プロセス中に、高速ポインタj
がi
ポインタが指す要素と異なる場合、それは新しい非反復要素に遭遇したことを意味し、新しい非反復要素をi
スローポインタの次の位置を設定し、同時にスロー針を設定します。 1 つi
前の位置に移動します。トラバーサルが終了すると、スロー ポインターi
の1
新しい配列の長さを加えた値になります。
以下の手順に従います。
-
2 つのポインター
i
とj
。どちらも配列の最初の要素を指します。 -
高速ポインタが配列の末尾に
j
到達する。
a.nums[i] != nums[j]
新しい非繰り返し要素が見つかったことを意味する場合は、その要素にnums[j]
コピーしnums[i+1]
、スロー ポインタを 1 位置i
後方に。b. 高速ポインタを 1 つ前の位置
j
に。 -
走査後、
i+1
新しい配列の長さである を返します。
int removeDuplicates(vector<int>& nums) {
if (nums.size() == 0) return 0; // 如果数组为空,直接返回 0
int i = 0; // 定义慢指针 i,初始时指向数组的第一个元素
for (int j = 1; j < nums.size(); j++) {
// 定义快指针 j,从数组的第二个元素开始遍历
if (nums[i] != nums[j]) {
// 如果快指针 j 指向的元素与慢指针 i 指向的元素不同
i++; // 将慢指针 i 向后移动一个位置
nums[i] = nums[j]; // 将快指针 j 指向的元素复制到慢指针 i 的下一个位置
}
}
return i + 1; // 返回新数组的长度
}
int removeDuplicates(vector<int>& nums) {
if (nums.size() == 0) return 0; // 如果数组为空,直接返回 0
int i = 0, j = 1; // 定义慢指针 i 和快指针 j,初始时分别指向数组的第一个元素和第二个元素
while (j < nums.size()) {
// 只要快指针 j 没有到达数组末尾
if (nums[i] != nums[j]) {
// 如果快指针 j 指向的元素与慢指针 i 指向的元素不同
i++; // 将慢指针 i 向后移动一个位置
nums[i] = nums[j]; // 将快指针 j 指向的元素复制到慢指针 i 的下一个位置
}
j++; // 将快指针 j 向后移动一个位置
}
return i + 1; // 返回新数组的长度
}
詳細なプロセス手順:
-
配列の長さを確認し、0 の場合は 0 を返します。
-
スロー ポインター i とファースト ポインター j の 2 つのポインターを初期化します。i は配列の最初の要素を指し、j は配列の 2 番目の要素を指します。
-
高速ポインタ j が配列の末尾に到達するまで配列を走査します。
a. nums[i] が nums[j] に等しくないかどうかを判断します。
b. nums[i] が nums[j] と等しくない場合は、新しい一意の要素が見つかったことを意味します。
i. スローポインタを 1 つ後ろの位置に移動します。
ii. nums[j] を nums[i] にコピーします。
c. nums[i] が nums[j] と等しい場合は、何も行いません。
d. 高速ポインタ j を 1 位置後方に移動します。
-
走査が終了すると、新しい配列の長さである i + 1 が返されます。
例として、配列 nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4] を考えてみましょう。
初期状態: i = 0, j = 1 nums = [0, 0, 1, 1, 1, 2, 2, 3, 3, 4]
横断プロセス:
- 最初のループ:
nums[i] == nums[j]
、何もしない、j = 2。 - 2 番目のループ:
nums[i] != nums[j],i = 1,nums[i] = nums[j],j = 3。 nums = [0, 1, 1, 1, 1, 2, 2, 3, 3, 4]
- 3 番目のサイクル:
nums[i] == nums[j]
、操作は実行されません、j = 4。 - 4 番目のサイクル:
nums[i] == nums[j]
、操作は実行されません、j = 5。 - 5 番目のサイクル:
nums[i] != nums[j],i = 2,nums[i] = nums[j],j = 6。 nums = [0, 1, 2, 1, 1, 2, 2, 3, 3, 4]
- 6 番目のサイクル:
nums[i] == nums[j]
、操作は実行されません、j = 7。 - 7 番目のサイクル:
nums[i] != nums[j],i = 3,nums[i] = nums[j],j = 8。 nums = [0, 1, 2, 3, 1, 2, 2, 3, 3, 4]
- 8 番目のサイクル:
nums[i] == nums[j]
、操作は実行されません、j = 9。 - 9 番目のループ:
nums[i] != nums[j],i = 4,nums[i] = nums[j],j = 10
(j が配列の最後に到達したため、ループから抜け出します)。nums = [0, 1, 2, 3, 4, 2, 2, 3, 3, 4]
ループが終了します。
この時点でi = 4
、新しい配列の長さは ですi + 1 = 5
。新しい配列は[0, 1, 2, 3, 4]。