目录
一、力扣第27题:原地移除元素
1.思路一:
2.思路二
3.思路三
二、力扣第88题:合并两个有序数组
1.思路一:
2.思路二:
3.思路三:
总结
一、力扣第27题:原地移除元素
题目链接:27. 移除元素 - 力扣(Leetcode)
题目描述:
1.思路一:
其实对于这道题而言,我们一开始最先想到的方法是这样的
假设我们有这样一个数组
我们先遍历一遍数组,寻找2,找到2以后,让后面的所有数据去全部依次覆盖,最后让数组当前的元素个数-1.
然后继续遍历
最后一次删除
就这样我们就删除了所有的元素,这种方法思考起来很简单,但其实是行不通的,因为时间复杂度太大了
我们计算时间复杂度是看最坏的情况,试想一下,我们最坏的情况就是全部的元素都需要删除,那么他的时间复杂度将达到N*(N-1+N-2+N-3+.....+1) ,因为我们本身就需要对整个数组进行一次遍历,第一个数据的删除一n-1次,第二个数据的删除要n-2次....最后一个数据的删除要1次。这个时间复杂度已经达到了立方级别,相当的大。
2.思路二
我们是这样想的,既然思路一的时间复杂度如此之大,那么我们可不可以这样思考,在开辟一个数组空间,将原来数组的值不等于2的数据依次拷贝到新的数组中。最后再把新数组的值拷贝到原来数组中。这样的话,我们就只需要一次遍历即可,这样时间复杂度就达到了O(N)
但是这样违背了提议,因为我们的空间复杂度也变成了O(1),所以这个方法肯定是不可以的
3.思路三
我们其实可以在思路二上进行改良,使用两个指针来实现我们的目的
如下图所示,我们定义两个指针src和dest。让他们都指向第一个元素
然后我们让src往后走,如果src的位置不是val,就将他放到dest的位置,然后两个指针都++
如果src的位置是val,那就只让src++
下面是第一步移动,src指向的不是2,所以两个指针都往后移动
这是第二步移动src指向的不是2,所以两个指针都往后移动
这是第三次移动src指向的是2,所以src移动
这是第四次移动src仍然指向的是2,所以继续src往后移动
这是第五次移动,此时src指向的不是2,所以将3赋给dest所指向的值,两个指针都移动
这是第六次移动,src指向的不是2,所以将src的值赋给dest,然后两个指针都向后移动
这是第七次移动,src指向的不是2,所以src的值赋给dest,然后两个指针都向后移动
这是第八次移动,src指向的仍然不是2,所以src要继续向后移动
此时src已经超出了数组的长度,所以现在遍历结束。dest之前,不包含dest本身的元素就是删除完2以后的数组,并且dest也代表的数组的长度,总共是5个元素
所以说这道题思路我们就想明白了,接下来就让我们来实现一下吧
int removeElement(int* nums, int numsSize, int val){
int src=0;
int dest=0;
while(src<numsSize)
{
if(nums[src] != val)
{
nums[dest]=nums[src];
dest++;
src++;
}
else
{
src++;
}
}
return dest;
}
已通过力扣用例
二、力扣第88题:合并两个有序数组
题目链接:88. 合并两个有序数组 - 力扣(Leetcode)
题目描述:
1.思路一:
对于这道题,我们应该能想到之前做过的一个题,也是合并两个有序数组,不过有所不同的是,那道题是将元素都放到第三个数组中,而这道题都是放在第一个数组中,这样一来,我们当然可以用之前那种思路,先弄一个第三个数组,然后放进去,然后将第三个数组的元素都弄到第一个数组中,但是这样显得太过于啰嗦了。而且空间复杂度也变大了。我们最好另寻他法
2.思路二:
和之前那道题目一样,我们可以不管什么东西,全部放在第一个数组中,然后对他进行排序。但是这样时间复杂度又变得很大了。
3.思路三:
我们这个思路是建立在第一个思路之上的,我们知道,正难则反。所以我们可以从反面来进行解答这道题,我们放在第三个数组中的思想是,找小的,然后放在第三个数组中,那我们这道题可以从最大的开始,找最大的数,放在第一个数组的最后一个位置。
我们画图来模拟一下我们的思路,如下图所示,我们创建三个变量,一个是end1用于记录数组1的下标的,一个是end2用于记录数组2的下标。然后就是end用于记录合并之后的数组下标
我们先让nums1[end1]和nums[end2]比较
如果nums1[end1]大,那么让nums1[end1]的值放入nums1[end]中,然后让end1--,end--
如果nums2[end2]大,那么让nums2[end2]的值放入nums1[end]中,然后让end2--,end--
如果最终end2<0了,那么直接停止即可
如果最终end1<0了,那么将nums2中剩余的元素放入nums1中
我们来模拟一下这个流程
第一次移动,6比3大,所以6移动到最后,end2和end--
第二次移动,5比3大,所以5移动,end和end2--
第三次移动,3比2大,所以3移动,end1和end--
第四次移动,两者一样大,随意移动一个即可,我们选择移动下面的。这样end2和end--
然后end2<0,所以直接结束即可
经过上面的分析,我们已经可以写出代码了,那么我们就来写出代码吧
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int end1=m-1;
int end2=n-1;
int end=m+n-1;
while(end1>=0 && end2>=0)
{
if(nums1[end1]>nums2[end2])
{
nums1[end]=nums1[end1];
end--;
end1--;
}
else
{
nums1[end]=nums2[end2];
end2--;
end--;
}
}
while(end2>=0)
{
nums1[end]=nums2[end2];
end--;
end2--;
}
}
总结
本次主要讲解了两道力扣题目:27.原地移除元素、88.合并两个有序数组
希望对大家有所帮助,如果对你有帮助,不要忘记一键三连哦!!!
想要知道后续更多更精彩的内容, 一定要关注我哦!!!