1.双指针的技巧
双指针大致分为二类,一个是快慢指针,剩下一个是左右指针,左右指针中,通常会将单调性与左右指针一起结合。
注意:这里所指的双指针在某一些题目中是指针,但大多数都是数组元素下标
接下来,用题目去说明
题一:移动零
1.1 链接
1.2 思路
前提:数组长度为n,数组为nums
首先定义两个变量des和cur,用cur去遍历整个数组,我们要实现[0,des]为非零,[dest+1,cur-1] 为零,[cur,n]为待处理数据,就拿[0,1,0,3,12]来说明,我们要实现数组分块的效果.
- 首先,cur位于元素下标为0处,des赋值为-1(这样是为了满足区间的合法性),我们先判nums[cur]是否为0;
- 若 nums [cur] 为0,那么我们让cur++,去找非0的数值,直到找到第一个非0的数,就停下来,
- 若 nums[cur] 不为0时,我们将 nums[des+1] 与 nums[cur] 进行交换(这步是因为,我们已经判断了[dest+1,cur-1]这个区间内数都为0) ,在des++,cur++,
- 然后我们在重复上述操作,直到cur>=n,就停止。
1.3代码
void Swap(int* e1,int* e2)
{
int tmp=*e1;
*e1=*e2;
*e2=tmp;
}
void moveZeroes(int* nums, int numsSize) {
int des=-1;
int cur=0;
while(cur<numsSize)
{
if(nums[cur]==0)
{
cur++;
}
else{
Swap(&nums[des+1],&nums[cur]);
des++;
cur++;
}
}
}
题二:删除有序数组里的重复项
1.1链接
26. 删除有序数组中的重复项 - 力扣(LeetCode)
1.2思路
前提:数组名为nums
定义两个指针,一个为slow,一个fast,我们让fast去遍历数组,去找与nums[slow]不同的值,找到了第一个不同的值,就停下。
- 如果nums[fast] !=nums[slow],那么就slow++,再将 nums[fast] 赋值给 nums[slow](注意当fast找到了第一个不同的值时,(slow,fast)之间都是与nums[slow]重合的数),再让fast++;
- 如果nums[fast] ==nums[slow],则让 fast++
- 在重复上述操作,直到 fast>=nums.size(),就结束
- 我们最终返回的时 slow+1,slow+1就时新数组的元素个数。
1.3代码
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int fast=0;
int slow=0;
//也可以理解重新开了一个数组,每次将进行筛选赋值
while(fast<nums.size())
{
if(nums[fast]!=nums[slow])//如果进入了for循环,
//那么则保证了在从slow(包括slow)到fast(不包括fast)都是相同的数;
{
slow++;
nums[slow]=nums[fast];
}
fast++;
}
return slow+1;
}
};
题三:快乐数
1.1链接
1.2思路
知识前提准备,鸽巢原理,有n个巢,和n+1个鸽子,那么至少会有一个巢鸟的数量>1。
首先,我们由题目可知,在判断这个一个数是否为快乐水,它只有两种可能,一是:最终这个数变成了1,二是:无限循环 但始终变不到 1。最终能到达1,其实也是相当于无限循环1。
下面我们来证明一下
- 首先这个数最大只能是2的31次方-1,那么也就是2,147,483,647
- 它<9,999,999,999,这个各个位的数的平方和为810,则2的31次方-1经过判断快乐水的操作后,其平方数和一定位于 [ 1, 810 ] 之间。
- 我们对2的31次方-1,进行811次这样的求平方数和的操作
- 由鸽巢原理可知,一定会有一个数重合,那么此时就构成了闭环。
- 那么我们也可以,确定它一定会出现一个闭环,只不过是闭环中的数是否相同而已。
相信大家看到上面画的图后,一定也想到了链表中如何判断循环链表的那道题了。
这里我们也采取一样的思路,定义一个快指针fast,一个慢指针slow,慢指针一次只往前走一步,快指针一次往前走2步,。由于快指针一直都比慢指针快并且这里一定会出现一个闭环,那么快指针一定会与慢指针相遇。(这就相当于二个人在操场跑步,一个人总比你快,那么你们一定会相遇的)
有空,可以去重新写一下环形链表
1.3代码
class Solution {
public:
int bitsum(int n) {
int sum = 0;
while (n) {
int m = n % 10;
sum += m * m;
n = n / 10;
}
return sum;
}
bool isHappy(int n) {
int slow = n;
int fast = bitsum(n);
while (slow != fast) {
slow = bitsum(slow);
fast = bitsum(bitsum(fast));
}
//当代码执行到这,就以为这,它们相遇了,就是出现值相等了,
//那么我们不必在往后了,因为在往后,也是在重复这个闭环而已。
//并且最后slow的位置一定是闭环的开始和结束那个点
return slow == 1;//判断slow是否为1
}
};
后续题目(思路是:双指针结合单调性)明天补上,