1. 双指针思想
常见的双指针有两种形式:一种是对撞指针、一种是快慢指针
1. 对撞指针:一般位于顺序结构中,也被称为左右指针。
- 对撞指针从两端向中间移动,⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。
- 对撞指针的终⽌条件⼀般是两个指针相撞或者错开(也可能在循环内部找到结果直接跳出循环),也就是:
(两个指针相撞)
(两个指针错开)
2. 快慢指针:⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。
- 这种⽅法对于处理环形链表或数组以及循环往复的问题⾮常有⽤。
- 快慢指针的实现⽅式有很多种,最常⽤的⼀种就是:
- 在⼀次循环中,每次让慢的指针向后移动⼀位,⽽快的指针往后移动两位,实现⼀快⼀慢。
2. 移动零
Leetcode283.移动零:https://leetcode.cn/problems/move-zeroes/
题目描述:
给定一个数组
nums
,编写一个函数将所有0
移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出:[1,3,12,0,0]
示例 2:
输入: nums = [0]
输出:[0]
2.1 题目解析
根据题目描述,通过区间的划分对数组进行操作,可以简单的理解为将整个数组划分为两块,「数组分两块」是⾮常常⻅的⼀种题型,主要就是根据⼀种划分⽅式,将数组的内容分成左右两部分。这种类型的题,⼀般就是使⽤「双指针」来解决。
2.2 算法思路
解决本题使用的是双指针算法:
在这里为了方便,可以直接使用数组的下标来进行指针的模拟,要想对数组进行分块,首先设置一个指针(cur)对数组进行遍历,要将非0放到左边还需要一个指针(dest)来对数组进行区域划分,那么这两个指针的作用分别是:
cur:从左向右扫描,遍历整个数组。
dest:已处理区间内,非0元素的最后一个位置。
在遍历的整个过程中这两个指针会将数组分为三个区间:
如何实现呢?
首先让cur和dest都指向数组的起始位置(或者让dest指向-1的位置),然后让cur指针向后遍历,这时cur指针会遇到两种情况:
1. 遇到0时,直接++cur,继续向后面走。
2. 遇到非0时,需要交换dest位置与cur位置的元素,然后再将dest和cur加1。
结束的条件cur遍历完整个数组。
2.3 代码实现
使用最简单的循环语句即可完成遍历和判断:
class Solution { public: void moveZeroes(vector<int>& nums) { int cur = 0, dest = 0; for(;cur < nums.size(); cur++) { if(nums[cur]) //非0再交换 swap(nums[dest++], nums[cur]); //后置++,使用完了再++进行迭代 //为0就继续向后面迭代 } } };
2.4 算法复杂度
该算法遍历一遍数组即可,时间复杂度:0(N)
没有开辟额空间,空间复杂度:O(1)
算法小总结:
数组分块,区间划分是在快速排序算法 中也有提到的,快速排序算法的关键就是进行区间的划分。
朋友们、伙计们,美好的时光总是短暂的,我们本期算法的分享就到此结束,欲知后事如何,请听下回分解~,最后看完别忘了留下你们弥足珍贵的三连喔,感谢大家的支持!