双指针算法--移除元素、删除有序数组中的重复项、合并两个有序数组

一、移除元素

1.题目

链接:https://leetcode.cn/problems/remove-element/description/

2.解法

定义两个整形变量leftright
left指针:标记有效元素的末尾(新数组索引)
right指针:遍历整个数组,查找有效元素

让它们同时指向数组的首元素即left = 0, right = 0;,让right运用循环while遍历数组元素,while执行条件为right < numsSize(数组长度),让nums[right]val比较,如果nums[right] != val,让nums[left] = nums[right] ,同时让left++,循环结束return left;(有效元素个数)

c 复制代码
int removeElement(int* nums, int numsSize, int val) {
    int left = 0;   // 左指针:标记有效元素的末尾(新数组索引)
    int right = 0;  // 右指针:遍历整个数组,查找有效元素
    
    // 右指针遍历完所有元素则结束
    while(right < numsSize)
    {
        // 找到不等于val的有效元素
        if(nums[right] != val)
        {
            // 将有效元素填充到左指针位置,左指针后移(扩大有效区间)
            nums[left++] = nums[right];
        }
        // 无论是否找到有效元素,右指针继续向后遍历
        right++;
    }
    
    // 左指针的值即为有效元素个数(新数组长度)
    return left;
}

代码还可以优化,若 left == right,说明当前元素本就该保留,无需赋值,直接移动双指针即可;只有当 left < right 时,才需要将 right 指向的有效元素覆盖到 left 位置,避免重复赋值。

c 复制代码
int removeElement(int* nums, int numsSize, int val) {
    int left = 0;   // 左指针:指向新数组下一个待填充位置(有效元素边界)
    int right = 0;  // 右指针:遍历原始数组寻找有效元素(不等于val的值)
    
    // 右指针遍历完所有元素则结束循环
    while (right < numsSize) 
    {
        // 当右指针找到有效元素(不等于val)时
        if (nums[right] != val) 
        {
            // 优化点:仅当左右指针不重叠时才赋值
            // 避免同一位置重复写入相同值(如数组开头无val时)
            if (left != right) 
            {
                nums[left] = nums[right];  // 将有效元素移到左指针位置
            }
            left++;  // 左指针后移,扩大有效元素区间
         }
        right++;  // 无论是否找到有效元素,右指针继续向后遍历
    }
    
    // 左指针的值即为有效元素的个数(新数组长度)
    return left;
}

二、删除有序数组中的重复项

1.题目

https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/

2.解题

  1. 定义两个整形变量leftright
    left指针:标记有效元素的末尾(新数组索引)
    right指针:从第2个元素开始寻找更大的新元素(因数组有序)
  2. right运用循环while遍历数组元素,while执行条件为right < numsSize(数组长度)
  3. if (nums[right] > nums[left]) left++,将新元素放到left指针位置
  4. 考虑数组只有一位元素的情况,这种情况就不需要任何操作直接返回原数组大小即可
  5. 循环结束return left + 1;(有效元素个数)
c 复制代码
int removeDuplicates(int* nums, int numsSize) {
    // 边界优化:空数组或只有一个元素时,直接返回原长度(无重复可删)
    if (numsSize <= 1) 
    {
        return numsSize;
    }
    
    int left = 0;   // 左指针:标记当前不重复元素的最后位置
    int right = 1;  // 右指针:从第2个元素开始寻找更大的新元素(因数组有序)
    
    while (right < numsSize) 
    {
        // 若右指针找到更大元素(即新的不重复元素)
        if (nums[right] > nums[left]) 
        {
            // 左指针前移后,将新元素放到左指针位置(合并操作,更紧凑)
            nums[++left] = nums[right];
        }
        right++;  // 右指针继续遍历
    }
    
    // 左指针索引+1即为不重复元素的个数
    return left + 1;
}

三、合并两个有序数组

1.题目

https://leetcode.cn/problems/merge-sorted-array/description

2.解题

  1. 输入:两个非递减序数组nums1(长度m+n,前m个有效元素)和nums2(长度n,全为有效元素)。

    目标:将nums2合并到nums1中,使合并后的nums1仍保持非递减序,原地修改(不使用额外数组)。

  2. 若从数组开头合并(正向遍历),nums1的有效元素可能被nums2的元素覆盖,导致数据丢失。可以使用逆向遍历(从末尾开始合并)。利用nums1末尾的n个预留空间,从后往前填充较大元素,避免覆盖有效数据。

  3. 定义三个指针:

    l1:指向nums1有效元素的末尾(初始值m-1)。

    l2:指向nums2有效元素的末尾(初始值n-1)。

    l3:指向nums1中待填充的位置(初始值(m+n)-1,即数组最后一位)。

  4. 逆向合并核心逻辑:

    比较nums1[l1]nums2[l2]的大小,取较大值放入nums1[l3]

    对应指针左移(l1--l2--),同时填充位置左移(l3--)。

    循环直到l1或l2遍历完(即其中一个数组的元素全部合并)。

  5. 处理剩余元素:
    若nums2还有剩余元素(l2 >= 0),说明nums1的元素已全部合并,直接将nums2剩余元素依次填充到nums1的前端(l3继续左移)。
    若nums1有剩余元素(l1 >= 0),无需处理,因为它们本就处于nums1的前端,且已有序。

c 复制代码
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
    int l1 = m - 1;    // 指向nums1有效元素的末尾(从后往前遍历)
    int l2 = n - 1;    // 指向nums2有效元素的末尾(从后往前遍历)
    int l3 = nums1Size - 1;  // 指向nums1的最终填充位置(从末尾开始往前填充)

    // 双指针逆向遍历,每次选择两个数组当前末尾的较大元素,填充到nums1末尾
    while (l1 >= 0 && l2 >= 0) 
    {
        // 比较nums1和nums2当前末尾元素,取较大值放入nums1的填充位置
        if (nums1[l1] >= nums2[l2]) 
        {
            nums1[l3--] = nums1[l1--];  // nums1的元素更大,填充后l1和l3均左移
        } else {
            nums1[l3--] = nums2[l2--];  // nums2的元素更大,填充后l2和l3均左移
        }
    }

    // 若nums2还有剩余元素(nums1已遍历完),直接将剩余元素填充到nums1前端
    // (nums1剩余元素已在正确位置,无需处理)
    while (l2 >= 0) 
    {
        nums1[l3--] = nums2[l2--];
    }
}
相关推荐
hoiii1872 小时前
Mean Shift目标跟踪算法MATLAB实现
算法·matlab·目标跟踪
励志的小陈2 小时前
复杂度算法题——旋转数组(三种思路)
c语言·数据结构·算法
tankeven2 小时前
HJ151 模意义下最大子序列和(Easy Version)
c++·算法
不光头强2 小时前
力扣78子集题解
算法·leetcode·深度优先
独断万古他化2 小时前
【算法通关】二叉树中的深搜:DFS 递归解题套路
算法·二叉树·深度优先·dfs·递归
㓗冽2 小时前
2026.03.27(第三天)
数据结构·c++·算法
sali-tec2 小时前
C# 基于OpenCv的视觉工作流-章44-直线卡尺
图像处理·人工智能·opencv·算法·计算机视觉
Magic--2 小时前
经典概率题:飞机座位分配问题(LeetCode 1227)超详细解析
算法·leetcode·职场和发展
urkay-3 小时前
Android 图片轮廓提取与重叠轮廓合并处理
android·算法·iphone