leetcode刷题-简单-26

26.删除有序数组中的重复项

方法1:使用STL(不完全符合原地修改的要求)

虽然这种方法更简洁,但它并不完全符合题目的“原地”要求,因为它可能在底层使用额外的空间。然而,了解如何利用C++的标准库来简化代码还是很有用的。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        nums.erase(unique(nums.begin(), nums.end()), nums.end());
        return nums.size();
    }
};

在C++中,nums.erase(unique(nums.begin(), nums.end()), nums.end());这行代码利用了标准模板库(STL)中的uniqueerase函数来删除数组(或向量)nums中的重复元素。这个表达式包含两个部分,理解起来需要拆分开来看:

  1. std::unique(nums.begin(), nums.end()):
    • std::unique是一个STL算法,它接收一个序列的开始和结束迭代器作为参数(在这里是nums.begin()nums.end(),代表nums向量的起始和结束位置)。
    • 它的作用是重排输入序列(nums向量),使得每个元素只出现一次且仅在其第一次出现的位置,而所有重复的元素被移动到序列的未尾。
    • std::unique不实际改变容器的大小;它返回一个迭代器,指向重排后的序列中“新的”逻辑结束位置,也就是第一个重复元素被移动到的位置。

在C++标准库中,std::unique 函数是用来移除来自已排序的序列(例如数组或向量)中的重复元素的。std::unique 函数通常与 std::sort 函数结合使用,因为它只能在已排序的序列上正确地移除重复项。

这个函数的作用是将重复的元素移动到序列的尾部,并返回一个指向新不重复序列尾部的迭代器。需要注意的是,它并不真正删除容器的元素,而是返回了一个指向容器中不重复序列新的逻辑结尾的迭代器。在这之后,可以使用容器的 erase 方法来删除重复的元素。

STL(Standard Template Library,标准模板库)算法是C++标准库的一部分,提供了一系列定义在头文件 、 和部分其他头文件中的模板函数,用于执行各种常见的算法操作,如排序、搜索、变换和计算等。STL算法作用于容器和其他序列上,通过迭代器与容器解耦,从而能够在不同类型的容器上执行相同的操作。
STL算法的特点包括:
泛型编程:STL算法通过模板实现,使得同一个算法可以用于不同类型的数据。
与容器无关:算法通过迭代器与容器进行通信,使得同一个算法可以应用于任何支持适当迭代器类型的容器上。
高效灵活:STL算法经过优化,提供了执行各种操作的高效方式。它们还允许通过函数对象和lambda表达式进行定制。
只读、非修改和修改算法:STL算法根据它们对元素的操作分为只读算法(不修改序列中的元素)、非修改算法(可能改变元素的顺序但不改变值)和修改算法(改变元素的值)。
一些常用的STL算法包括:
排序和搜索:std::sort、std::stable_sort、std::partial_sort、std::binary_search、std::lower_bound等。
变换:std::transform、std::replace、std::replace_if等。
数值操作:std::accumulate、std::inner_product、std::adjacent_difference等,这些定义在头文件中。
分区和排列:std::partition、std::nth_element、std::next_permutation等。
查找和比较:std::find、std::find_if、std::equal、std::mismatch等。
删除和替换:std::remove、std::remove_if、std::unique等。

  1. nums.erase(iterator1, iterator2):
    • erasestd::vector的成员函数,它删除位于两个迭代器iterator1iterator2之间的元素,包括iterator1指向的元素,但不包括iterator2指向的元素。
    • 在这个表达式中,iterator1std::unique返回的迭代器(指向重排后序列的“新”结束位置),而iterator2nums.end()
    • 通过调用erase,向量nums实际上删除了所有重复的元素,即从std::unique返回的迭代器到原序列末尾的所有元素。

因此,整个表达式nums.erase(unique(nums.begin(), nums.end()), nums.end());实现了删除nums向量中所有重复元素的目的,并且修改了向量的大小,使其仅包含唯一元素。这是一种简洁且高效地在STL兼容容器中删除重复元素的方法。但需要注意的是,这个方法假定nums已经是排序的,因为std::unique只能删除连续的重复元素。如果nums未排序,则需要先进行排序。

第一次回忆

class Solution {
public:
    int removeDuplicates(vector<int>& nums)  {
       nums.erase(nums.unique(nums.begin(),nums.end()),nums.end())
       return nums();
    }
};

GPT修改

#include <vector>
using namespace std;

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        // 正确的使用 unique,并将返回的迭代器作为 erase 的起点
        nums.erase(unique(nums.begin(), nums.end()), nums.end());
        // 返回修改后的数组的大小,而不是调用 nums() 
        return nums.size();
    }
};
  1. uniquestd::vector 类型没有的成员函数,应该是 std::unique,并且它属于 <algorithm> 头文件,所以使用时需要确保已经包含了这个头文件。
  2. unique(nums.begin(), nums.end()) 返回一个迭代器,指向去重后容器新的逻辑末尾,erase 函数接受两个迭代器作为参数,表示要删除元素的范围,您的调用方式是正确的,但括号使用有误。
  3. 返回值应该是 nums.size(),用于返回数组的长度,而不是 nums(),后者看起来像是在尝试调用 nums 作为一个函数,这是不正确的。

此外,请确保你的代码文件开头包含了 <vector><algorithm> 头文件,因为 std::vector 类型定义在 <vector> 中,而 std::unique 函数定义在 <algorithm> 中。

方法2:使用额外的标记数组(不推荐)(我第一次想到的是这样)

这种方法使用一个额外的数组来标记哪些元素是唯一的。虽然这种方法可以工作,但它不满足题目的原地修改要求,并且效率低于双指针法。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if (nums.empty()) return 0;
        vector<int> uniqueNums;
        uniqueNums.push_back(nums[0]);
        for (int i = 1; i < nums.size(); ++i) {
            if (nums[i] != nums[i - 1]) {
                uniqueNums.push_back(nums[i]);
            }
        }
        nums = uniqueNums;
        return nums.size();
    }
};

方法3:双指针法(原地修改)

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        if (nums.empty()) return 0;
        int k = 1;
        for (int i = 1; i < nums.size(); ++i) {
            if (nums[i] != nums[i - 1]) {
                nums[k++] = nums[i];
            }
        }
        return k;
    }
};

这段代码首先检查数组是否为空。如果不为空,它初始化k为1,因为至少第一个元素是唯一的。然后,它遍历数组,每次遇到与前一个元素不同的元素时,就将该元素复制到k指针的位置,并将k增加1。遍历结束后,k就是数组中唯一元素的数量,同时数组的前k个元素就是这些唯一元素,它们保持了原始顺序。这个方法只需要一次遍历,所以时间复杂度是O(n),其中n是数组nums的长度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值