[ソートされた配列内の重複を削除]

ソートされた配列内の重複を削除する

昇順の配列を指定した場合nums、各要素が 1 回だけ表示されるように、繰り返される要素を所定の位置で削除し、削除された配列の新しい長さを返してください。要素の相対的な順序は一貫している必要があります。次に、nums内の。

nums一意の要素の数が であることを考慮するとk、ソリューションが確実に合格するには次のことを行う必要があります。

  • の最初の要素に、最初にに出現ようnums配列を変更します。およびのサイズは重要ではありません。numsknumsnumsnums
  • 返品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配列を走査するために使用されます。走査プロセス中に、高速ポインタjiポインタが指す要素と異なる場合、それは新しい非反復要素に遭遇したことを意味し、新しい非反復要素をiスローポインタの次の位置を設定し、同時にスロー針を設定します。 1 つi前の位置に移動します。トラバーサルが終了すると、スロー ポインターi1新しい配列の長さを加えた値になります。

以下の手順に従います。

  1. 2 つのポインターij。どちらも配列の最初の要素を指します。

  2. 高速ポインタが配列の末尾にj到達する。
    a.nums[i] != nums[j]新しい非繰り返し要素が見つかったことを意味する場合は、その要素にnums[j]コピーしnums[i+1]、スロー ポインタを 1 位置i後方に。

    b. 高速ポインタを 1 つ前の位置jに。

  3. 走査後、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;  // 返回新数组的长度
}

詳細なプロセス手順:

  1. 配列の長さを確認し、0 の場合は 0 を返します。

  2. スロー ポインター i とファースト ポインター j の 2 つのポインターを初期化します。i は配列の最初の要素を指し、j は配列の 2 番目の要素を指します。

  3. 高速ポインタ 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 位置後方に移動します。

  4. 走査が終了すると、新しい配列の長さである 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]

横断プロセス:

  1. 最初のループ: nums[i] == nums[j]、何もしない、j = 2。
  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. 3 番目のサイクル: nums[i] == nums[j]、操作は実行されません、j = 4。
  4. 4 番目のサイクル: nums[i] == nums[j]、操作は実行されません、j = 5。
  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. 6 番目のサイクル: nums[i] == nums[j]、操作は実行されません、j = 7。
  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. 8 番目のサイクル: nums[i] == nums[j]、操作は実行されません、j = 9。
  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]。

おすすめ

転載: blog.csdn.net/u013454780/article/details/130567457