27. 移除元素 26. 删除有序数组中的重复项 88. 合并两个有序数组(双指针遍历)

下面的几道题,都运用一个双指针(下标)遍历法

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指向的元素等于valsrc向后走,des不变
在这里插入图片描述
src指向的值不等于val,所以将这个值放到des指向的空间中,接着srcdes都向后移
在这里插入图片描述
接下来的步骤以此类推,最终会得到一个合适的数组

但是这个方法显然不满足题中要求的原地修改,但是我们可以借助这个思想,只不过是在原数组上进行操作

srcdes都指向原数组,其余步骤都与上面那个方法类似
在这里插入图片描述

最开始src指向的元素等于valsrc向后走,des不变
在这里插入图片描述
接着src指向的元素的值不等于val,把这个值赋给des指向的空间中,接着src des向后挪
在这里插入图片描述
src指向的元素的值不等于val,把这个值赋给des指向的空间中,接着src des向后挪
在这里插入图片描述

src指向的元素等于valsrc向后走,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指向第二个元素
如果dessrc指向的元素相同,就src++
如果dessrc指向的元素不同,因为此前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中,如果还是按照归并做法从前往后操作则会覆盖的值
所以这道题我们从后往前归并
在这里插入图片描述
begin1begin2中选出较大的值,放到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]);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_64116522/article/details/129163974