顾得泉:个人主页
个人专栏:《Linux操作系统》 《C/C++》 《LeedCode刷题》
键盘敲烂,年薪百万!
双指针简介
对撞指针从两端向中间移动。一个指针从最左端开始,另一个从最右端开始。然后逐渐往中间逼近。
对撞指针的终止条件一般是两个指针相遇或者错开(也可能在循环内部找到拿果直接跳出循
环),也就是:
快慢指针:又称为龟兔赛跑算法,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列结构上移动。
其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使用快慢指针的思想。
快慢指针的实现方式有很多种,最常用的—种就是:在一次循环中,每次让慢的指针向后移动一位,而快的指针往后移动两位,实现一快一慢。
一、移动零
题目描述
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例 1:
输入: nums =[0,1,0,3,12]
输出:[1,3,12,0,0]
示例 2:
输入: nums =[0]
输出:[0]
提示:
解法
在本题中,我们可以用一个cur 指针来扫描整个数组,另一个dest指针用来记录非零数序列的最后一个位置。根据cur在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。在cur遍历期间,使[0, dest]的元素全部都是非零元素,[dest + 1, cur – 1]的元素全是零。
a.初始化 cur = 0(用来遍历数组),dest = -1(指向非零元素序列的最后一个位置。因为刚开始我们不知道最后一个非零元素在什么位置,因此初始化为-1)
b.cur依次往后遍历每个元素,遍历到的元素会有下面两种情况
i.遇到的元素是0 ,cur直接++。因为我们的目标是让[dest + 1, cur – 1]内的元素全都是零,因此当cur遇到o的时候,直接++,就可以让 o_在cur – 1的位置上,从而在[dest + 1, cur – 1]内;
ii.遇到的元素不是0,dest++,并且交换cur位置和dest位置的元素,之后让cur++,扫描下一个元素。
因为dest指向的位置是非零元素区间的最后一个位置,如果扫描到一个新的非零元素,那么它的位置应该在dest +1的位置上,因此dest先自增1;
dest++之后,指向的元素就是0元素(因为非零元素区间末尾的后一个元素就是0)因此可以交换到cur所处的位置上,实现[0,dest]的元素全部都是非零元素,[dest+ 1, cur – 1]的元素全是零
代码实现
class Solution {
public:
void moveZeroes(vector<int>& nums)
{
int dest = -1, cur = 0;
while(cur < nums.size())
{
if(nums[cur])
swap(nums[++dest],nums[cur]);
cur++;
}
}
};
二、复写零
题目描述
给你一个长度固定的整数数组 arr
,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。
示例 1:
输入:arr = [1,0,2,3,0,4,5,0] 输出:[1,0,0,2,3,0,0,4] 解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]
示例 2:
输入:arr = [1,2,3] 输出:[1,2,3] 解释:调用函数后,输入的数组将被修改为:[1,2,3]
提示:
解法
如果「从前向后」进行原地复写操作的话,由于/的出现会复写两次,导致没有复写的数「被覆盖掉」。因此我们选择「从后往前」的复写策略。
但是「从后向前」复写的时候,我们需要找到「最后一个复写的数」,因此我们的大体流程分两步:
i.先找到最后一个复写的数;
b.找到最后一个复写的数︰
判断cur位置的元素:
如果是0的话,dest往后移动两位;。否则,dest往后移动一位
i.如果越界,执行下面三步:
2. cur向移动一步;
3. dest向前移动两步
d. 从cur位置开始往前遍历原数组,依次还原出复写后的结果数组:
i.判断cur位置的值:
1.如果是0 :dest以及dest – 1位置修改成0,dest -= 2
2.如果非零:dest位置修改成0,dest -= 1 ;
ii. cur–,复写下一个位置
代码实现
class Solution {
public:
void duplicateZeros(vector<int>& arr)
{
int cur = 0, dest = -1, n = arr.size();
for(cur; cur < n; cur++)
{
if(arr[cur])
dest++;
else
dest += 2;
if(dest >= n - 1)
break;
}
if(dest == n)
{
arr[n-1] = 0;
cur--;
dest -= 2;
}
while(cur >= 0)
{
if(arr[cur])
arr[dest--] = arr[cur--];
else
{
arr[dest--] = 0;
arr[dest--] = 0;
cur--;
}
}
}
};
三、快乐数
题目链接:
题目描述
如果 n
是 快乐数 就返回 true
;不是,则返回 false
示例 1:
输入:n = 19 输出:true 解释: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1
示例 2:
输入:n = 2 输出:false
提示:
1 <= n <= 231 - 1
解法
算法思路:
根据上述的题目分析,我们可以知道;当重复执行的时候,数据会陷入到一个「循环」之中。而「快慢指针」有一个特性。就是在一个圆圈中,快指针总是会追上慢指针的,也就是说他们总会相遇在一个位置上。如果相遇位置的值是1,那么这个数一定是快乐数;如果相遇位置不是1的话,那么就不是快乐数。
补充知识:
a.把数n每一位的数提取出来:
ii. n /= 10干掉个位;
直到n的值变为0 ;
b.提取每一位的时候,用一个变量tmp记录这一位的平方与之前提取位数的平方和
代码实现
class Solution
{
public:
int Sum(int n)
{
int sum = 0;
while(n)
{
int t = n % 10;
sum += t * t;
n /= 10;
}
return sum;
}
bool isHappy(int n)
{
int slow = n, fast = Sum(n);
while(slow != fast)
{
slow = Sum(slow);
fast = Sum(Sum(fast));
}
return slow == 1;
}
};
结语:今日的刷题分享到这里就结束了,希望本篇文章的分享会对大家的学习带来些许帮助,如果大家有什么问题,欢迎大家在评论区留言~~~
原文地址:https://blog.csdn.net/m0_71746526/article/details/134795826
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_42760.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!