一、移除元素
1.题目
链接:https://leetcode.cn/problems/remove-element/description/

2.解法
定义两个整形变量left、right
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.解题
- 定义两个整形变量
left、right
left指针:标记有效元素的末尾(新数组索引)
right指针:从第2个元素开始寻找更大的新元素(因数组有序) - 让
right运用循环while遍历数组元素,while执行条件为right < numsSize(数组长度) if (nums[right] > nums[left])left++,将新元素放到left指针位置- 考虑数组只有一位元素的情况,这种情况就不需要任何操作直接返回原数组大小即可
- 循环结束
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.解题
-
输入:两个非递减序数组nums1(长度m+n,前m个有效元素)和nums2(长度n,全为有效元素)。
目标:将nums2合并到nums1中,使合并后的nums1仍保持非递减序,原地修改(不使用额外数组)。
-
若从数组开头合并(正向遍历),nums1的有效元素可能被nums2的元素覆盖,导致数据丢失。可以使用逆向遍历(从末尾开始合并)。利用nums1末尾的n个预留空间,从后往前填充较大元素,避免覆盖有效数据。
-
定义三个指针:
l1:指向nums1有效元素的末尾(初始值m-1)。
l2:指向nums2有效元素的末尾(初始值n-1)。
l3:指向nums1中待填充的位置(初始值(m+n)-1,即数组最后一位)。
-
逆向合并核心逻辑:
比较
nums1[l1]和nums2[l2]的大小,取较大值放入nums1[l3]。对应指针左移(l
1--或l2--),同时填充位置左移(l3--)。循环直到l1或l2遍历完(即其中一个数组的元素全部合并)。
-
处理剩余元素:
若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--];
}
}