目录
- [27. 移除元素-力扣](https://leetcode.cn/problems/remove-element/description/?languageTags=c)
- [26. 删除有序数组中的重复项](https://leetcode.cn/problems/remove-duplicates-from-sorted-array/)
- [88. 合并两个有序数组](https://leetcode.cn/problems/merge-sorted-array/)
下面的几道题,都运用一个双指针(下标)遍历法
27. 移除元素-力扣
示例1:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
示例2:
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
这道题最容易想到的思想是开辟一个新数组,然后遍历原数组,如果原数组中的某个值不等于val
的值,就把这个值放到新数组中
如图:
最开始src
指向的元素等于val
,src
向后走,des
不变
src
指向的值不等于val
,所以将这个值放到des
指向的空间中,接着src
和des
都向后移
接下来的步骤以此类推,最终会得到一个合适的数组
但是这个方法显然不满足题中要求的原地修改,但是我们可以借助这个思想,只不过是在原数组上进行操作
让src
和des
都指向原数组,其余步骤都与上面那个方法类似
最开始src
指向的元素等于val
,src
向后走,des
不变
接着src
指向的元素的值不等于val
,把这个值赋给des
指向的空间中,接着src
des
向后挪
src
指向的元素的值不等于val
,把这个值赋给des
指向的空间中,接着src
des
向后挪
src
指向的元素等于val
,src
向后走,des
不变
此时,src已经遍历出了数组,遍历结束,可以看到实际上操作后的数组就是[2,2]
,长度是2,也正好是作为下标的des
的值,所以最后返回des
的值。
代码如下:
int removeElement(int* nums, int numsSize, int val) {
int des = 0;
for (int src = 0; src < numsSize; src++) {
if (nums[src] != val) {
nums[des] = nums[src];
des++;
}
}
return des;
}
26. 删除有序数组中的重复项
这道题的思想与上一题思维类似,也是运用双指针遍历法
这道题的做法是:
定义2个指针,一个作为des
指向第一个元素,一个作为src
指向第二个元素
如果des
与src
指向的元素相同,就src++
如果des
与src
指向的元素不同,因为此前des
已经保存了之前的值,所以先des++
,再把src
的值放到des
中,再src++
代码如下:
int removeDuplicates(int* nums, int numsSize){
int src = 1;
int des = 0;
while(src<numsSize)
{
if(nums[src]==nums[des])
{
src++;
}
else
{
nums[++des] = nums[src++];
}
}
return des+1;
}
88. 合并两个有序数组
合并2个有序数组,这里可以使用归并排序的思想,但是这题与归并思想有些区别
这道题是把值最后都归到数组nums1
中,如果还是按照归并做法从前往后操作则会覆盖的值
所以这道题我们从后往前归并
在begin1
和begin2
中选出较大的值,放到des
中,然后des--
,以及对应元素较大的那个begin减1
接着还有个问题:
- 如果
begin2
先循环完,因为数组都是有序的,所以这是已经合并结束 - 如果
begin1
先循环完,nums2
中的部分数据可能还没有合并到nums1
中,所以这里可以把nums2
中的元素拷贝到nums1
中,拷贝的个数其实是des+1
代码如下:
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int des = nums1Size-1;
int begin1 = m-1;
int begin2 = n-1;
while(begin1>=0&&begin2>=0)
{
if(nums1[begin1]>nums2[begin2])
{
nums1[des] = nums1[begin1];
begin1--;
des--;
}
else if(nums1[begin1]<=nums2[begin2])
{
nums1[des] = nums2[begin2];
begin2--;
des--;
}
}
if(begin2<0)
{
return;
}
else if(begin1<0)
{
memmove(nums1,nums2,sizeof(int)*(des+1));
}
}
下面还有一个牛客网的题,也是运用双指针(下标)遍历法
牛客网:BC98 序列中删除指定数字
代码如下:
#include <stdio.h>
int main()
{
//输入各个值
int N= 0;
scanf("%d",&N);
int arr[N];
for(int i=0;i<N;i++)
{
scanf("%d",&arr[i]);
}
int val = 0;
scanf("%d",&val);
//删除指定数字
int des = 0;
for(int src=0;src<N;src++)
{
if(arr[src]!=val)
{
arr[des] = arr[src];
des++;
}
}
//输出修改后的序列
for(int i = 0;i<des;i++)
{
printf("%d ",arr[i]);
}
}