26. 删除排序数组中的重复项 27. 移除元素 双指针

题目:

  给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

  不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 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。

  你不需要考虑数组中超出新长度后面的元素。

解答:

首先是自己的解答:

  根据提示,使用双指针,也叫快慢指针,index1从首部移动, index2向后移动直到值与index1不同,则将 index2及之后的元素移动到index1+1的位置,重复直至index2抵达末位,然后返回的长度为:index1+1,因为index1是索引,比当前不重复元素少一。

  代码如下:

//26. 删除排序数组中的重复项
//原地删除重复元素,并且返回结果的长度int
//双指针
int removeDuplicates(vector<int>& nums) 
{
    if (nums.size() < 2)
        return nums.size();

    //排序
    sort(nums.begin(), nums.begin() + nums.size());

    int idx1 = 0, idx2 = 1;
    while (idx2 < nums.size())
    {
        while (idx2 < nums.size() && nums[idx1] == nums[idx2])
            idx2++;
        if (idx2 == nums.size())
            return idx1 + 1;

        for (int i = idx1+1; i < idx2; i++)
        {
            nums[i] = nums[idx2];
        }

        //test
        for (auto val : nums)
        {
            cout << val << "\t";
        }
        cout << endl;

        idx1++;
        idx2++;
    }

    return idx1 + 1;
}

  虽然提交后通过了,但是时间、空间效率很差。

  看解答后,发现只要把index2处不重复的元素复制到index1+1即可,减少元素的移动次数,代码如下:

int removeDuplicates(vector<int>& nums) {
        if (nums.size() < 2)
            return nums.size();

        //sort
        sort(nums.begin(), nums.begin() + nums.size());

        int idx1 = 0, idx2 = 1;
        while (idx2 < nums.size())
        {
            if (nums.at(idx1) != nums.at(idx2))
            {
                //如果不等,把idx2的元素放到idx1++的位置
                idx1++;
                nums[idx1] = nums[idx2];
            }
                
            //如果idx2 与 idx1 相等,则j++
            idx2++;
        }

        return idx1 + 1;
    }

小结:

  刷题后,多看题解,最好敲一遍学习学习。

 题目27:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

 

示例 1:

给定 nums = [3,2,2,3], val = 3,

函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。

你不需要考虑数组中超出新长度后面的元素。
示例 2:

给定 nums = [0,1,2,2,3,0,4,2], val = 2,

函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。

注意这五个元素可为任意顺序。

你不需要考虑数组中超出新长度后面的元素。

解答:

27题与26题类似,放到一起写。先自己写的代码,使用两个index在数组中移动,index找到第一个==val的值,然后index2找到后面不等于val的值,然后使用一个变量交换这两个位置的值“:

int removeElement(vector<int>& nums, int val) {
        if (nums.size() == 0)
            return 0;
        else if (nums.size() == 1 && nums[0] != val)
            return nums.size();

        int idx1 = 0, idx2 = 1;
        int tmp = 0;
        while (idx2 < nums.size())
        {
            while (idx1 < nums.size() && nums[idx1] != val)
            {
                idx1++;
                idx2++;
            }
                
            if (idx1 == nums.size() || idx2 >= nums.size())
                break;

            if (nums[idx2] == val)
            {
                idx2++;
                continue;
            }
            
            //此时,idx1=val,idx2++找到一个不等的元素
            tmp = nums[idx2];
            nums[idx2] = nums[idx1];
            nums[idx1] = tmp;
            idx1++;
            idx2 = idx1 + 1;
        }

        return idx1;
    }

解答的代码:真tm简洁,自己写的就是一坨,解答中的代码可以在num[i]=num[j]之前加个判断,当i == j时赋值这步可以跳过,减少操作。

public int removeElement(int[] nums, int val) {
    int i = 0;
    for (int j = 0; j < nums.length; j++) {
        if (nums[j] != val) {
            nums[i] = nums[j];
            i++;
        }
    }
    return i;
}

 

posted @ 2020-11-18 19:06  adfas  阅读(108)  评论(0编辑  收藏  举报