算法复习:双指针(对撞指针、快慢指针)
一、快慢指针: leedcode 142. 环形链表 II
快慢指针的思想是设置慢指针slow和快指针fast,slow每次走一步,fast每次走两步,如果有环fast指针和slow指针必然相遇,相遇时
定义新的指针p从head开始和slow从当前位置起每次都走一步,直到相遇,相遇的位置就是环的入口。
class Solution { public: ListNode *detectCycle(ListNode *head) { int lable=0; struct ListNode *slow,*fast,*pp; if(head==NULL) return NULL; if(head->next==NULL) return NULL; slow=head->next; if(slow->next==NULL) return NULL; fast=slow->next; while(slow!=fast)// 步骤一:使用快慢指针判断链表是否有环 { if(fast->next==NULL) { lable=1; break; } fast=fast->next;//快指针走两步 if(fast->next==NULL) { lable=1; break; } fast=fast->next; slow=slow->next;//慢指针走一步 } if(lable==1) return NULL; pp=head; while(pp!=slow)// 步骤二:若有环,找到入环开始的节点 { pp=pp->next; slow=slow->next; } return pp; } };
int main() { struct ListNode *head,*p,*q; head=NULL; q=(ListNode*)malloc(sizeof(ListNode));//malloc的方法 q->next=NULL; int num; cout<<"Input num"<<endl; scanf("%d",&num); for(int i=0;i<num;i++)//建链表插入链表 { p=(ListNode*)malloc(sizeof(ListNode)); cout<<"Input number"<<endl; p->next=NULL; scanf("%d",&p->val); if(i==0) head=p; else q->next=p; q=p; } int loop; cout<<"Input loop"<<endl; scanf("%d",&loop); if(loop==-1) q->next=NULL; else//建循环链表 { p=(ListNode*)malloc(sizeof(ListNode)); p=head; for(int i=0;i<loop;i++) { p=p->next; } q->next=p; } p=detectCycle(head); cout<<p->val<<endl; return 0; }
二、对撞指针:leedcode 11. 盛最多水的容器
对撞指针要求两个指针up和down分别从前后两端向中间走,指定一个指针更新规则
本题计算面积,水的上限由短板决定,因此更新规则是选取短的那一个边的方向向中间移动,直到指针碰撞
int min(int a,int b) { if(a>b) return b; else return a; } int maxArea(vector<int>& height) { int up=0,down=height.size()-1; int area=down*min(height[0],height[down]),tmp_area=0; while(up<down) { tmp_area=(down-up)*min(height[up],height[down]); if(tmp_area>area) area=tmp_area; if(height[up]>height[down]) down--; else up++; } return area; }
leedcode 125. 验证回文串
双指针根据规则向中间靠拢即可
class Solution { public: bool isPalindrome(string s) { int up=0,down=s.size()-1; int lable=0; while(up<=down) { if((s[up]>='0'&&s[up]<='9')||(s[up]>='A'&&s[up]<='Z')||(s[up]>='a'&&s[up]<='z')) { if(s[up]>='A'&&s[up]<='Z') s[up]=s[up]+('a'-'A'); } else { up++; continue; } if((s[down]>='0'&&s[down]<='9')||(s[down]>='A'&&s[down]<='Z')||(s[down]>='a'&&s[down]<='z')) { if(s[down]>='A'&&s[down]<='Z') s[down]=s[down]+('a'-'A'); } else { down--; continue; } if(s[up]==s[down]) { up++; down--; } else { lable=1; break; } } if(lable==1) return false; else return true; } };
leedcode 167. 两数之和 II - 输入有序数组
class Solution { public: vector<int> twoSum(vector<int>& numbers, int target) { int up=0,down=numbers.size()-1; while(up<=down) { if(numbers[up]+numbers[down]>target) { down--; continue; } if(numbers[up]+numbers[down]<target) { up++; continue; } if(numbers[up]+numbers[down]==target) break; } vector<int>result; result.push_back(up+1); result.push_back(down+1); return result; } };
面试题57 - II. 和为s的连续正数序列
class Solution { public: vector<vector<int>> findContinuousSequence(int target) { vector<vector<int>>result; int head=1,tail=1; int s=1; while(head<target) { if(s<target) { tail++; s+=tail; } else if(s>target) { s-=head; head++; } else if(s==target) { vector<int> tmp; for(int i=head;i<=tail;i++) { tmp.push_back(i); } result.push_back(tmp); tail++; s+=tail; } } return result; } };
三、其他指针
有空间限制不能使用第二个数组转存,因此先遍历一遍统计空格‘ ’的数量,然后留足空间(2倍空格数量),
down指针从后往前扫,up指针从原串最后往前扫,碰到‘ ’就替换成‘0’‘2’‘%’,直到up down相撞
class Solution { public: void replaceSpace(char *str,int length) { int num=0,i; for(i=0;str[i]!='\0';i++) { if(str[i]==' ') num++; } int len_final=i+num*2; char *down=str+len_final; char *up=str+i; while(up!=down) { if(*up==' ') { *down--='0'; *down--='2'; *down--='%'; } else *down--=*up; up--; } return; } };
56. 合并区间
#include<algorithm> #include<string.h> #include<stdlib.h> struct donser { int i; int j; }; int qsor(const void* a,const void*b) { return (*(donser *)a).i-(*(donser *)b).i; } class Solution { public: vector<vector<int>> merge(vector<vector<int>>& inte) { vector<vector<int>>result; struct donser my[10002]; if(inte.size()==0) return result; for(int i=0;i<inte.size();i++) { my[i].i=inte[i][0]; my[i].j=inte[i][1]; } qsort(my,inte.size(),sizeof(donser),qsor); my[inte.size()].i=inte[inte.size()-1][0]; my[inte.size()].j=inte[inte.size()-1][1]; int x=my[0].i,y=my[0].j; for(int i=0;i<inte.size()+1;i++) { if(x<=my[i].i&&y>=my[i].i)//有交集 更新y { y=max(y,my[i].j); if(i==inte.size())//处理最后 { vector<int>tmp; tmp.push_back(x); tmp.push_back(y); result.push_back(tmp); } } else//无交集 存储 { vector<int>tmp; tmp.push_back(x); tmp.push_back(y); result.push_back(tmp); if(i==inte.size()) break; x=my[i].i; y=my[i].j; } } return result; } };
75. 颜色分类
四指针,两个用于标记位置,两个用于查找
class Solution { public: void sortColors(vector<int>& nums) { if(nums.size()<=1) return; int x=0,y=nums.size()-1;//扫描指针 int x1=0,y1=nums.size()-1;//位置指针 int equ1=0,equ2=0;//重合标记 while(x<=y) { if(y!=y1) equ2=1; if(x!=x1) equ1=1; if(equ1==0)//前一半重合 { if(nums[x]==0)//继续 { x++; x1++; continue; } else if(nums[x]==2)//交换 { if(nums[y]!=2) { int tmp=nums[x]; nums[x]=nums[y]; nums[y]=tmp; continue; } } else if(nums[x]==1)//处理 { equ1=1; x++; continue; } } if(equ2==0)//后一半重合 { if(nums[y]==2)//继续 { y--; y1--; continue; } else if(nums[y]==0)//交换 { if(nums[x]!=0) { int tmp=nums[x]; nums[x]=nums[y]; nums[y]=tmp; continue; } if(nums[x]==0) { equ2=1; } } else if(nums[x]==1)//处理 { equ2=1; y--; continue; } } //处理x不重合情况 if(nums[x]==2)//和y1交换 { int tmp=nums[x]; nums[x]=nums[y1]; nums[y1]=tmp; y1--; y=min(y,y1); if(y1==y) equ2=0; } else if(nums[x]==0)//和x1交换 { int tmp=nums[x]; nums[x]=nums[x1]; nums[x1]=tmp; x1++; x=max(x,x1); } else if(nums[x]==1) x++; //处理y不重合情况 if(nums[y]==2)//和y1交换 { //cout<<"***"<<nums[y]<<" "<<nums[x]<<endl; int tmp=nums[y]; nums[y]=nums[y1]; nums[y1]=tmp; y1--; y=min(y,y1); } else if(nums[y]==0)//和x1交换 { int tmp=nums[y]; nums[y]=nums[x1]; nums[x1]=tmp; x1++; x=max(x,x1); if(x1==x) equ1=0; } else if(nums[y]==1) y--; } return ; } };