LeetCode之旅(C/C++):26. 删除排序数组中的重复项

版权声明:欢迎转载,不必客气。 https://blog.csdn.net/CSDN_FengXingwei/article/details/89189274

PS:不明之处,请君留言,以期共同进步!

题目描述:

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。

示例 2:

给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}

代码实现:

//第一种
int removeDuplicates(int* nums, int numsSize) 
{
    for(int i = 0; i < numsSize - 1; ++i)
    {
        if(nums[i] == nums[i+1])
        {
            for(int j = i; j < numsSize - 1; ++j)
            {
                nums[j] = nums[j + 1];
            }
            numsSize -= 1;
            i--;
        }
    }
    return numsSize;
}

//说明:
//这是最一般的做法,外层循环用于遍历数组以判断相邻两个元素是否相同,
//内层循环用于遍历“后续元素”从而把它们依次往前移动一个位置,为了应
//对多个相邻元素都相同的情况,在进行完内循环之后要进行【i–】的操作,
//从而抵消外循环中【i++】的操作。

//第二种
int removeDuplicates(int* nums, int numsSize) 
{
    int i = 0, tail = 0;
    if(0 == numsSize)
        return 0;
    for(; i < numsSize - 1; i++)
        if(nums[i] != nums[i + 1])
            nums[tail++] = nums[i];//等价于nums[tail] = nums[i];tail++;
    nums[tail] = nums[i];//前面一定要进行numsSize是否为0的判断,否则当numsSize为0时会产生缓冲区溢出的错误
    return tail + 1;
}

//说明:
//tail指向新数组的尾部位置,虚位以待那个“不同的数”的到来。
//i用于遍历数组,以判断相邻两数是否相同,如果不同,就把i指
//向的数保存到tail指向的位置;如果相同,则什么都不做,i继
//续往后走,直到遇见两个不同的数,此前i已经遇到若干个相同的
//数了,现在要把i指向的、同时也是这若干个相同的数中最后一个
//数保存到tail指向的位置。然后i继续往后走并继续进行以上的判
//断和操作,当i走到整个数组的末尾时,它就走到尽头了,此时要
//把它指向的数保存到tail指向的位置。

//第三种(1)
int removeDuplicates(int* nums, int numsSize) 
{
    int i = 1, tail = 0, same = 0;
    while(i < numsSize)
    {
        if(nums[tail] != nums[i])
            nums[++tail] = nums[i];
        else
            ++same;
        ++i;
    }
    return numsSize - same;
}
//第三种(2)
int removeDuplicates(int* nums, int numsSize) 
{
    int i = 1, tail = 0;
    if(0 == numsSize) 
        return 0;
    for(; i < numsSize; ++i)
        if(nums[tail] != nums[i])
            nums[++tail] = nums[i];
    return tail + 1;
}

//说明:tail指向新数组的尾部,当nums数组不为空时,它的第一个元素肯定要加
//入新数组的,所以i从下标1开始往后走,当它遇到一个与tail指向的元素不同的数
//时,就先让tail往后走一步,并且把那个数保存到tail现在指向的新位置,当它碰到
//一个与tail指向的元素相同的数时,就什么也不做,接着往后找,直到走到nums数
//组的尽头。
//以上两种写法,一种要判断numsSize是否为0,一种不需要判断,是因为最后返回
//值的写法不同。

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

//说明:
//本来想用迭代器,但是发现用了比不用还麻烦,于是放弃了,
//将前面的C语言程序稍稍改写一下就行了。

总结:

在三种解题思路中,我最喜欢第三种思路,不仅很简单,而且时间复杂度低。

猜你喜欢

转载自blog.csdn.net/CSDN_FengXingwei/article/details/89189274
今日推荐