前两天有些事情耽搁了,还是要赶快赶上进度的。
给你一个数组 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)。
给你一个按 非递减顺序 排序的整数数组 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;
}
};