#双指针分类
**1.左右指针
例题:反转链表
class Solution {
public:
ListNode* reverseList(ListNode* head) {
//三个指针分别表示前一个节点,当前节点和下一个节点
ListNode *pre=NULL;
ListNode *cur=head;
ListNode* next;
while(cur)
{
next=cur->next;
cur->next=pre;
pre=cur;
cur=next;
}
return pre;
}
};
2.对撞指针(解决有序数组的数字之和或反转数组之类的可以两边开工的问题)
模板:指定指针初始位置,设置指针移动方法,给定结束条件。
例题:反转数组
class Solution {
public:
void reverse(int []nums){
int left=0;
int right=nums.length()-1;
while(left<right){
int temp=nums[left];
nums[left]=nums[right];
nums[right]=temp;
}
}
};
3.快慢指针(两个指针移动速度不一样)**
解决问题:移除元素;判断链表是否含有环;已知链表有环,返回环的起始位置;寻找链表中点;寻找链表倒数第k个元素;
模板:
1.初始位置:慢指针指向第一个元素位置,快指针指向下一个元素位置
2.移动方法:慢指针步数加一,快指针步数加二(反正两个指针的速度要不同)
3.结束条件:两指针重合或快指针先到达终点。
例题:
环形链表
class Solution {
public:
bool CycleList(ListNode *head) {
if(head==NULL)
return false;
//快慢指针,两指针都先指向头结点
ListNode* L=head;
ListNode* R=head;
while(R!=NULL&&R->next!=NULL)
{
L=L->next;//走1步
R=R->next->next;//走两步
//当慢指针遇到快指针时,说明链表存在环
if(L==R)return true;
}
return false;
}
};
滑动窗口
原理:将双层循环变为单层变量循环问题,使两个指针一左一右构成一个窗口.
解决问题:数组,字符串的子元素,字串的问题,例如找到满足xx的最x的区间的xx ,满足查找一定条件的连线区间的性质
模板:初始化left=-1,right=0;[left,right]称为一个窗口
指针移动方法:不断增加right,直到窗口字符串符合要求,停止增加right,增加left缩减窗口直到不符合要求
例题:
最长回文字符串
所谓回文字串,就是一个字符串从左往右读和从右往左读是完全一样的,例如:“a”,“aba”,"abcddcba"是回文字符串,"dffgd"则不是。
本题采用中心扩展的方法,即把给定的字符串的每一个字母当做中心,向两边扩展,但要考虑奇数和偶数。
string findLongestPalindrome(string &s)
{
const int length=s.size();
int maxlength=0;
int start;
for(int i=0;i<length;i++)//长度为奇数
{
int j=i-1,k=i+1;
while(j>=0&&k<length&&s.at(j)==s.at(k))
{
if(k-j+1>maxlength)
{
maxlength=k-j+1;
start=j;
}
//向两边扩散,j和k包含的元素构成一个滑动窗口,依次扩大窗口
j--;
k++;
}
}
for(int i=0;i<length;i++)//长度为偶数
{
int j=i,k=i+1;
while(j>=0&&k<length&&s.at(j)==s.at(k))
{
if(k-j+1>maxlength)
{
maxlength=k-j+1;
start=j;
}
j--;
k++;
}
}
if(maxlength>0)
return s.substr(start,maxlength);
return NULL;
}