一、移除元素
有一个数组 nums 和一个变量 val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度,不要使用额外的数组空间
示例:输入:nums={3,2,2,3},val=3 输出:2,nums={2,2}
输入:nums={0,1,2,2,3,0,4,2},val=2 输出:5,nums={1,3,0,4,2}
思路:使用双指针法(快慢指针)
创建两个变量 src(源数据)和 dst(目标数据),
1)若src指向的值为val,src++,
2)若不是val,nums[dst]=nums[src],src++,dst++
(src是快指针,用来遍历数组,而dst是慢指针,用来存放有效的数组元素)
代码实现:
//方式1
int removeElement(int* nums,int numsSize,int val)
{
int src = 0;
int dst = 0;
while(src < numsSize)
{
if(nums[src] == val)
{
src++;
}
else
{
//赋值,两指针++
nums[dst] = nums[src];
dst++;
src++;
}
}
//此时dst的刚好就是新数组的有效长度(有效元素个数)
return dst;
}
//方式二
int removeElement(int* nums,int numsSize,int val)
{
int src = 0;// src是慢指针,指向下一个有效数字
int dst = 0;// dst是快指针,遍历数组
for(src = 0;src < numsSize; src++)
{
if(nums[src] != val)// 当前元素不等于val
{
nums[dst] = nums[src];// 将有效元素复制到慢指针位置
dst++;// 慢指针前进
}
}
return dst;// 返回新长度(有效元素个数)
}
int main()
{
int nums[] = {3,2,2,3};
int val = 3;
int numsSize = sizeof(nums)/sizeof(nums[0]);
printf("原始数组:");
for(int i = 0;i < numsSize; i++)
{
printf("%d ",nums[i]);
}
printf("\n");
int newSize = removeElement(nums,numsSize,val);
printf("移除%d后数组的新长度为%d\n",val,newSize);
printf("新数组:");
for (int i = 0; i < newSize; i++)
{
printf("%d ", nums[i]);
}
printf("\n");
return 0;
}
接下来我们顺便实现一下可以额外添加数组的方式:
思路:将移除val后的元素存放在 tmp[] 数组中
首先先创建好 nums数组,数组元素为3,2,2,3;接着创建val变量,即要移除的元素,肯定需要遍历数组,所以需要计算好nums数组的长度,可以先将nums数组,即原始的数组先打印出来与后续进行对比(数组需要遍历打印),
然后我们写一个函数来求移除val后的数组长度,函数的参数有原始数组,数组长度以及val,在函数内部,我们先开辟一个新的数组tmp(使用动态开辟,记得对返回值进行判断),再加一个变量count,记录非val的元素,同时作为tmp数组的下标使用,接下来遍历一下原数组,筛选一下非val的元素(for+if),然后赋值给新的数组tmp,最后将结果重新复制到原始数组中,接着对tmp进行free释放然后置为空指针,返回count(移除后数组的新长度)
int removeElement(int* nums,int numsSize,int val)
{
//创建临时数组
int* tmp = (int*)malloc(numsSize*sizeof(int));
int count = 0;//记录非val的元素
if(tmp == NULL)
{
perror("malloc");
return 1;
}
// 遍历原数组,筛选非 val 元素
for(int i = 0;i < numsSize; i++)
{
if(nums[i] != val)
{
tmp[count] = nums[i];// 将有效元素存入临时数组
count++;
}
}
//将结果复制到原数组
for(int i = 0;i < count; i++)
{
nums[i] = tmp[i];
}
//释放
free(tmp);
tmp = NULL;
return count;
}
int main()
{
int nums[] = {3,2,2,3};
int val = 3;
int numsSize = sizeof(nums)/sizeof(nums[0]);
printf("原始数组:");
for(int i = 0;i < numsSize; i++)
{
printf("%d ",nums[i]);
}
printf("\n");
int newSize = removeElement(nums,numsSize,val);
printf("移除%d后数组的新长度为%d\n",val,newSize);
printf("新数组:");
for (int i = 0; i < newSize; i++)
{
printf("%d ", nums[i]);
}
printf("\n");
return 0;
}
二、合并两个数组
有两个按非递减顺序排列的整数数组nums1和nums2,另有两个整数m和n,分别表示nums1和nums2中的元数个数,请你合并nums2到nums1中,使合并后的数组同样按非递减顺序排列
示例:
输入:nums1={1,2,3,0,0,0}; m=3,
nums2={2,5,6}; n=3
输出:{1,2,2,3,5,6}
思路:我们还是按第一道题的思路进行,使用双指针,从前往后开始遍历,假设nums1数组采用L1变量,nums2数组使用L2变量,接下来拿两个数组中的元素进行比大小,以给出的示例为例,此时nums1[L1]=3 > nums2[L2]=2,那么就要将nums2[L2]这个元素移到nums1[L1]这个位置上,而我们注意到此时nums1[L1]位置原本的元素就被覆盖掉了,所以这样的思路是不对的
那么应该如何做呢?还是用指针的方式,要从后往前开始遍历比大小(比谁大,谁大谁往后放),除此之外还需要增加一个变量L3,用来表示nums1数组中的最后一个元素的位置,而L1,L2两个指针并不是简单的从后面开始,而是数组的第三个元素开始从后往前遍历(以nums2数组元素个数为准,两个数组对齐元素个数,而题目也说了m,n=3分别表示两个数组的元素个数,这就可以直接使用)
具体操作:(1) L2先出循环
(2)L1先出循环,nums2中还有数据未放到nums1中
代码实现:
(需要遍历数组,因此需要求数组长度,但是我们已知m,n,可以用这两个变量来求)
void merge(int* nums1,int m,int* nums2,int n)
{
int L1 = m-1;
int L2 = n-1;
int L3 = m+n-1;
while(L1>=0 && L2>=0)//只要有一个条件不满足就退出循环
{
if(nums1[L1] < nums2[L2])
{
nums1[L3--] = nums2[L2--];
}
else
{
nums1[L3--] = nums1[L1--];
}
}
//除了循环有两种情况:L1>=0或L2>=0,只需要处理L2>=0的情况(说明L2中的数据还没有完全放入到nums1中)
while(L2 >= 0)
{
nums1[L3--] = nums2[L2--];
}
//此时nums1中包含了nums2中的数据,nums1是升序数组
}
int main()
{
int nums1[] = {1,2,3,0,0,0};
int nums2[] = {2,5,6};
int m = 3;
int n = 3;
merge(nums1,m,nums2,n);
for(int i = 0;i < m+n; i++)
{
printf("%d ",nums1[i]);
}
return 0;
}