算法练习 Day2

前两天有些事情耽搁了,还是要赶快赶上进度的。

力扣27. 移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与
val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素 nums 的其余元素和 nums 的大小并不重要。
  • 返回 k。
用户评测:

评测机将使用以下代码测试您的解决方案:

int[] nums = [...]; // 输入数组 int val = ...; // 要移除的值 int[]
expectedNums = [...]; // 长度正确的预期答案。
                            // 它以不等于 val 的值排序。

int k = removeElement(nums, val); // 调用你的实现

assert k == expectedNums.length; sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {
    assert nums[i] == expectedNums[i]; }

如果所有的断言都通过,你的解决方案将会 通过。

正如题目所说,删除元素,这道题目最直接的做法就是遍历容器,将其中与 val 的值相同的元素删除掉。代码比较简单,但是可以温习一下迭代器的用法(删除迭代器元素后,迭代器会自动指向下一个元素的位置,要记得接收返回值)

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        for (vector<int>::iterator it = nums.begin();
        it != nums.end();) {
            if (*it == val) {
                it = nums.erase(it);
            } else {
                it++;
            }
        }
        return nums.size();
    }
};

当然,这样方便的原因正是因为它是使用的容器的原因,在删除元素后,后面的元素会自动向前补充。但是如果元素无法直接删除,就像数组一样,只能覆盖应该怎么办呢?暴力解法当然是可行的,当你遍历到与 val 相同的元素时,将后面的元素都向前移动,时间复杂度也就是等差数列求和加上n,O(n^2)。
这里可以用到一个技巧,也就是快慢指针法(双指针法),将寻找 val 值和向前移动同时进行:(图片来自代码随想录)

实现代码如下:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        // 分别定义快慢指针(这里用的是索引值)
        int slowp = 0;
        for (int fastp = 0; fastp < nums.size(); fastp++) {
            if (nums[fastp] != val) {
                nums[slowp] = nums[fastp];
                slowp++;
            }
        }
        return slowp;
    }
};

代码逻辑和上面的 gif 相同:当没有找到 val 时,fast 和 slow 一起++,fast 指向的值覆盖 slow 指向的值,当找到 fast 找到 val 的值时,fast++。时间复杂度仅为 O(n)。

力扣997. 有序数组的平方

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10] 输出:[0,1,9,16,100] 解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11] 输出:[4,9,9,49,121]

这道题的暴力解法不难,只需要先遍历数组,将所有的元素平方,再将所有的元素按照从小到大排序就好了。代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        // 遍历
        for (int i = 0; i < nums.size(); i++) {
            nums[i] *= nums[i];
        }
        // 排序
        sort(nums.begin(), nums.end());
        
        return nums;
    }
};

虽然写法很简单,但是不能忘了 sort 方法也是有时间复杂度的(快速排序:O(nlogn))。因此,有没有更快的解法呢?注意到是整数的非递减数列,因此平方后最大值一定出现在队首(较小的负数)或者队尾(较大的正数),所以只要采用双指针法,不断取出最大的那个数,缩小列表的大小就好了。

这边我一开始思路狭隘了,总想着在一个数组里一次性完成平方和换位操作,事实上这样是很困难的,正确的做法是将平方后的数比较后放入新的数组中。具体代码如下:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        int left = 0;
        int right = nums.size() - 1;

        for (int i = 0; i <= right; i++) {
            nums[i] *= nums[i];
        }
		
		// 采用双指针策略
        vector<int> result(right+1);
        for (int i = right; i >= 0; i--) {
            if (nums[left] < nums[right]) {
                result[i] = nums[right];
                right--;
            } else {
                result[i] = nums[left];
                left++;
            }
        }

        return result;
    }
};

你可能感兴趣的:(算法,c++,leetcode)