第一题:移除元素
题目描述:
给你一个数组nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用O(1)
额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100
//题目框架
int removeElement(int* nums, int numsSize, int val){
}
方法一:
可以使用覆盖删除的方式来解决这道题。
遍历所给数组,如果遇到val
,就去寻找数组后面不是val
的值进行交换,直到数组遍历完。
参考代码如下:
//时间复杂度:O(n^2)
//空间复杂度:O(1)
int removeElement(int* nums, int numsSize, int val)
{
int i = 0;
for(i = 0; i < numsSize; ++i)
{
if(nums[i] != val)
{
;
}
else//nums[i]==val
{
for(int j = i + 1; j < numsSize; ++j)
{
//num[j]!=val,才能和val交换
//num[j]==val,就跳过
if(nums[j] != val)
{
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
break;
}
}
}
}
//遍历数组,求移除元素后数组的长度
for(i = 0; i < numsSize; ++i)
{
if(nums[i] == val)
{
break;
}
}
return i;
}
方法二:
可以使用前后指针的方式来解决这道题。
定义两个指针变量front
和back
,当back
遇到的值不是val
,就把他赋值给front
位置;back
遇到的值是val
,`back``就跳过,继续寻找,直到遍历数组完成。
参考代码如下:
//时间复杂度:O(n)
//空间复杂度:O(1)
int removeElement(int* nums, int numsSize, int val)
{
int* front = nums;
int* back = nums;
while(back < nums + numsSize)
{
if(*back != val)
{
*front = *back;
++front;
++back;
}
else
{
++back;
}
}
return front - nums;
}
第二题:删除有序数组中的重复项
题目描述:
给你一个升序排列的数组nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。
不要使用额外的空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
1 <= nums.length <= 3 * 10^4
-10^4 <= nums[i] <= 10^4
nums 已按 升序 排列
//题目框架
int removeDuplicates(int* nums, int numsSize){
}
方法一:
这道题可以使用前后指针的方式来解决。
定义两个指针变量front
和back
,back
在front
后一个位置(back=front+1),当back
遇到的值和front
相等的话,back
就跳过;back
遇到的值和front
不等的话,就赋值给front
的下一个位置。
参考代码如下:
//时间复杂度:O(n)
//空间复杂度:O(1)
int removeDuplicates(int* nums, int numsSize)
{
if(numsSize<2)
{
return numsSize;
}
int* front = nums;
int* back = nums + 1;
while (back < nums + numsSize)
{
if (*back == *front)
{
++back;
}
else
{
++front;
*front = *back;
++back;
}
}
return front - nums + 1;
}
第三题:合并两个有序数组
题目描述:
给你两个按 非递减顺序 排列的整数数组nums1
和nums2
,另有两个整数m
和n
,分别表示nums1
和nums2
中的元素数目。
请你 合并nums2
到nums1
中,使合并后的数组同样按 非递减顺序 排列。
nums1.length == m + n
nums2.length == n
0 <= m, n <= 200
1 <= m + n <= 200
-10^9 <= nums1[i], nums2[j] <= 10^9
//题目框架
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
}
方法一:
额外开辟一个m+n
大小的数组,通过nums1
和nums2
两个数组元素的比较进行归并,最后将归并后的数据顺序拷贝回num1
数组。
参考代码如下:
//时间复杂度:O(m+n)
//空间复杂度:O(m+n)
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
int* arr = (int*)malloc((m + n) * sizeof(int));
int* end1 = nums1 + m;
int* end2 = nums2 + n;
int* ptr = arr;
while (nums1 < end1 && nums2 < end2)
{
if (*nums1 < *nums2)
{
*ptr = *nums1;
++nums1;
++ptr;
}
else
{
*ptr = *nums2;
++nums2;
++ptr;
}
}
if (nums1 == end1)
{
while(nums2 < end2)
{
*ptr = *nums2;
++ptr;
++nums2;
}
}
else
{
while (nums1 < end1)
{
*ptr = *nums1;
++ptr;
++nums1;
}
}
//将数据拷贝回nums1数组
nums1 = end1 - m;
for(int i = 0; i < m + n; ++i)
{
nums1[i] = arr[i];
}
}
方法二:
这种方法是从nums1和nums2的尾部开始比较大小进行归并的,将较大值直接归并到nums1数组的尾部位置。
参考代码如下:
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n)
{
int* dest = nums1 + m + n - 1;
int* src1 = nums1 + m - 1;
int* src2 = nums2 + n - 1;
while (src1 >= nums1 && src2 >= nums2)
{
if (*src1 > *src2)
{
*dest = *src1;
--dest;
--src1;
}
else
{
*dest = *src2;
--dest;
--src2;
}
}
//nums2没有归完需要继续归
//因为归并的目标数组就是nums1,所以nums1没有归完也不需要继续循环归并了
while(src2 >= nums2)
{
*dest = *src2;
--dest;
--src2;
}
}