LeetCode解题总结--双指针
双指针解题多用于链表、数组等问题当中。
双指针的难度在于:
1、一开始可能很难想到
2、变式很多
3、指针并不是具体指的函数中的“指针”,而是一种思想。例如设置两个不同的可动标志位,也是”双指针“
下面以具体的LeetCode题目补充解释:
题目汇总:
141. 环形链表 (经典题,引入快慢指针思想)
845. 数组中的最长山脉(双指针的变式应用)
1、LeetCode 141. 环形链表
环形链表这道题在我看来,是理解快慢指针思想的最典型的题目。
通过利用快慢指针的步长差,并且结合链表的环状结构,只要链表中存在着环,那么,不论时间的长短,快指针和慢指针总会相遇。
想象这么一个场景:两辆车一快一慢,在一段直线距离后驶入环形跑道,那么只要给予一定时间,快的车一定会比慢的车快上一整圈,从而相遇。而用快慢指针正是模拟了这种思想,来检测环形。
一旦我们了解了快慢指针的思想,那么,在很多问题上,我们都可以想到使用双指针来解决问题。需要注意的问题只不过是在于双指针的变式很多,需要我们结合题目来具体分析。
快慢指针解题的思路图解:
class Solution {
public:
bool hasCycle(ListNode *head)
{
if(head==nullptr||head->next==nullptr)
return false;
ListNode* fast = head;
ListNode* slow = head;
while(slow->next!=nullptr&&fast->next!=nullptr)
{
slow = slow->next;//慢指针每次前进一步
if(fast->next->next == nullptr)
return false;
fast = fast->next->next;//快指针每次前进两步
if(fast==slow)
return true;
}
return false;
}
};
2、LeetCode 26. 删除排序数组中的重复项
本题的目标是为了删除重复项,但是不需要删除所有的重复项,只需要将不同的项提到前面即可。这样第一个想到的思路就是:
遍历整个数组,每当遇到不一样的元素就将其提到前面。这样就会产生一个问题,如何确保在交换时,可以确定位置。只要我们使用一个标志位记录不重复的元素的最后位置,每次遇到不同的元素就将元素放在标志位的后一个,并更新标志位即可。
具体的过程可以看下图:
class Solution {
public:
int removeDuplicates(vector<int>& nums)
{
if(nums.size()==0)
return 0;
int p1 = 0;
int cur = nums[0];
for(int i=0;i<nums.size();i++)
{
if(cur!=nums[i])
{
cur = nums[i];
nums[++p1] = nums[i];
}
}
return p1+1;
}
};
本题和上一题的差别其实并不算很大,因为只要搞懂了LeetCode 26,其实差别就在于,如何多使用一个计数器,来实现“最多出现两次”的这一限定条件。
class Solution {
public:
int removeDuplicates(vector<int>& nums)
{
if(nums.size()==0)
return 0;
if(nums.size()==1)
return 1;
int numCounter=1;
int P1 = 0;
int cur = nums[0];
for(int i=1;i<nums.size();i++)
{
if(cur!=nums[i])
{
cur=nums[i];
P1++;
nums[P1] = nums[i];
numCounter=1;
continue;
}
if(numCounter<2)
{
P1++;
numCounter++;
nums[P1] = cur;
}
}
return P1+1;
}
};
4、845. 数组中的最长山脉(双指针的变式应用)
这道题中,我的做法是,结合“中心扩张”思想和双指针来解题的。
①首先,找到一个符合条件的山脉顶点
②在顶点两侧使用双指针向两端扩张,直到不符合要求为止。
③两个指针最终的坐标值的差即为长度,不断更新max值即可。
个人感觉只要掌握了上述的几个解题思路,遇到类似的问题,第一时间也会想到利用双指针来结题,接下来就是根据题目具体制定解题步骤了!
posted on 2022-08-13 16:15 DylanYeung 阅读(40) 评论(0) 编辑 收藏 举报