【双指针】双指针算法详解两道经典OJ【力扣27,力扣26,力扣38】超详细算法教程
【双指针】双指针算法详解两道经典OJ【力扣27,力扣26,力扣38】超详细算法教程
今天又又到了我们刷力扣题的时间啦!
今天博主给大家带来的三道题是:
27. 移除元素
26. 删除有序数组中的重复项
88. 合并两个有序数组
这三道题,都是双指针算法题的一个入门题,掌握这三道题,认识双指针算法,是我们今天的目标!
前言
那么这里博主先安利一下一些干货满满的专栏啦!
作者: #西城s
这是我的主页:#西城s
在食用这篇博客之前,博主在这里介绍一下其它高质量的编程学习栏目:
数据结构专栏:数据结构 这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
算法专栏:算法 这里可以说是博主的刷题历程,里面总结了一些经典的力扣上的题目,和算法实现的总结,对考试和竞赛都是很有帮助的!
力扣刷题专栏:Leetcode 想要冲击ACM、蓝桥杯或者大学生程序设计竞赛的伙伴,这里面都是博主的刷题记录,希望对你们有帮助!
C的深度解剖专栏:C语言的深度解剖 想要深度学习C语言里面所蕴含的各种智慧,各种功能的底层实现的初学者们,相信这个专栏对你们会有帮助的!
OJ27 移除元素
题目描述
算法分析
题目的意思其实很简单,其实就是把一个数在数组里面去掉。
那么很容易想到的思路就是:
- 开一个空间,将符合条件的拷贝下来,但是按照这种方法我们时间虽然是
O(n)
,但我们的空间就是O(n)
了,不是最优解法。 - 另一种比较好想到的方法就是,写一个删除单个数字的函数,遍历数组,但是这样的时间就不是
O(n)
了,因为我们删除元素的时候需要挪动数据,这样效率是非常低的。
这时候,我们可以想想双指针的方法。
双指针其实就是对一个数组用两个下标进行处理(或者两个指针)
所以这题我们可以采用覆盖的方法来解决:
定义两个指针
prev
和head
,head
跑在前面,prev
跑在后面。
实现代码
int removeElement(int* arr, int numsSize, int val) {
//1 2 2 2 3 4 5 6 2
int* ahead = arr;
int* end = arr + numsSize - 1;
int* prev = arr;
while (ahead <= end) {
if (*ahead == val) {
ahead++;
numsSize--;
}
else {
*prev = *ahead;
prev++;
ahead++;
}
}
return numsSize;
}
OJ26 删除有序数组中的重复项
题目描述
算法分析
不用多说,我们的目标肯定一定要在时间O(n),空间O(1)内完成的。
同样,和上一道题类似的思路,使用双指针,覆盖元素的方式来解决。
- 这道题唯一的两个区别,就是我们要留一个,不要完全删掉,那其实,我们只需要将上一题的
prev
,在覆盖之前,先++
以下就行了。同时,因为是删除重复项,所以我们的prev
和ahead
在初始化的时候,ahead
要先往前一个位置。
这个算法其实就是一个经典的去重算法。
实现代码
int removeDuplicates(int* nums, int numsSize) {
//去重算法
//双指针
//1 2 2 3 4 5 6 2 2 2 2
int* ahead = nums + 1;
int* prev = nums;
int* end = nums + numsSize - 1;
while (ahead < end) {
if (*ahead == *prev) {
ahead++;
}
else {
prev++;
*prev = *ahead;
ahead++;
}
}
return prev-nums;
}
OJ88 合并两个有序数组
题目描述
算法分析
其实这个合并,我们最容易想到的,其实就是把两个数组搞在一起,再排序一下就行了。
但是,我们要意识到,排序的代价是比较大的。因此,我们要采用双指针,归并算法。
其实这个算法就是归并排序所用的思想。
这里博主提供两种思路:
第一种思路: 如图:
这种思路和归并排序的思路有点类似,最后我们再将新开数组的内容拷贝回原来的位置就行了。
第二种思路:
我们同样可以采用覆盖方法,思路和前面两题十分类似,这里就不赘述了。
注意:
这里的遍历要从后往前,这个画个图就能很好理解了,因为从前往后跑,会覆盖原来有用的元素,所以我们要从后往前覆盖,找大的放到nums1
里面去。
第二种思路的实现我们可以达到空间复杂度可以到O(1),时间复杂度O(n),博主这里提供第二种思路的实现代码
实现代码
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
int* end1 = nums1 + m - 1;
int* end2 = nums2 + n - 1;
int* end = nums1 + m + n - 1;
while ((end1 >= nums1) && (end2 >= nums2)) {
if (*end1 > *end2) {
*end-- = *end1--;
}
else if (*end1 < *end2) {
*end-- = *end2--;
}
}
while (end2 - nums2 >= 0) {
*end-- = *end2--;
}
}
尾声
看到这里相信你对双指针算法的这两道OJ已经有一定的理解了,如果你觉得有帮助的话请不要吝啬你们的点赞收藏关注和转发噢!