题目
给你一个数组 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。
你不需要考虑数组中超出新长度后面的元素。
数组删除知识
数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖
自写代码(错误)
思路
1.直接让需要删去的值被后一个的值覆盖
2.定义一个j变量,记录被覆盖的次数,返回长度为原来数组长度-j
/*
1.直接让需要删去的值被后一个的值覆盖
2.定义一个j变量,记录被覆盖的次数,返回长度为原来数组长度-j
输出
2
nums[0] = 3
nums[1] = 2 后面的值也是2,后面的2赋值给了前面的2,所以这种情况不能满足要求
nums[2] = 3
nums[3] = 3
*/
# include<stdio.h>
int removeElement(int* nums, int numsSize, int val) {
int i = 0;
int j = 0;
int l;
for (i; i < numsSize; ++i)
{
if (nums[i] == val)
{
nums[i] = nums[i + 1];
j++;
}
}
l = numsSize - j;
printf("%d\n", l);
return l;
}
int main(void)
{
int i;
int nums[4] = { 3, 2, 2, 3 };
removeElement(nums, 4, 2);
for(i = 0; i<4; ++i)
{
printf("nums[%d] = %d\n",i, nums[i]);
}
}
/*
将要删去的值与后一个互换
输出
1
nums[0] = 3
nums[1] = 2 后面的值也是2,后面的2与前面的2互换,所以这种情况不能满足要求
nums[2] = 3
nums[3] = -858993460 最后一个是2,和后面的互换,会出现错误情况
*/
# include<stdio.h>
int removeElement(int* nums, int numsSize, int val) {
int i = 0;
int j = 0;
int m;
int l;
for (i; i < numsSize; ++i)
{
if (nums[i] == val)
{
m = nums[i]; //互换
nums[i] = nums[i + 1];
nums[i + 1] = m;
j++;
}
}
l = numsSize - j;
printf("%d\n", l);
return l;
}
int main(void)
{
int i;
int nums[4] = { 3, 2, 2, 3 };
removeElement(nums, 4, 2);
for (i = 0; i < 4; ++i)
{
printf("nums[%d] = %d\n", i, nums[i]);
}
}
代码随想录
暴力解法(两个for循环)
思路
1.一层循环遍历整个数组
2.一层循环替换出现的目标值
int removeElement(int* nums, int numsSize, int val){
int i = 0;
for(i; i<numsSize; ++i)
{
if(nums[i] == val)
{
for(int j = i + 1; j<numsSize; ++j)
{
nums[j - 1] = nums[j];
}
i--; //保证下一次循环从i开始,因为i有可能替换后还是目标值 eg.{3,2,2,3} 第1个2被替换后还是2,确保替换后的2被后面的3替换
numsSize--;
}
}
return numsSize ;
}
注意
第二层循环中要加i–来确保每个目标值都能被删除
双指针法
思路
一个循环两个指针(快指针和慢指针)
快指针负责找除了需要删除数据元素的其他数据元素
慢指针负责指向删除后新数组的下标
int removeElement(int* nums, int numsSize, int val){
int slowInex = 0;
for(int fastInex = 0; fastInex<numsSize; fastInex++){
if(nums[fastInex] != val){ //条件为不等于val
nums[slowInex] = nums[fastInex];
slowInex++; //可以直接写成nums[slowInex++] = nums[fastInex];
}
}
return slowInex;
}
相向双指针
int removeElement(int* nums, int numsSize, int val){ {
int leftIndex = 0;
int rightIndex = numsSize - 1;
while (leftIndex <= rightIndex) {
// 找左边等于val的元素
while (leftIndex <= rightIndex && nums[leftIndex] != val){ //条件是不等于val
++leftIndex;
}
// 找右边不等于val的元素
while (leftIndex <= rightIndex && nums[rightIndex] == val) { //条件是等于val
-- rightIndex;
}
// 将右边不等于val的元素覆盖左边等于val的元素
if (leftIndex < rightIndex) {
nums[leftIndex++] = nums[rightIndex--];
/*
nums[leftIndex] = nums[rightIndex];
leftIndex++;
rightIndex--;
*/
}
}
return leftIndex; // leftIndex一定指向了最终数组末尾的下一个元素
}