
双指针的算法原理,通过两个指针在一个for循环下完成两个for循环的工作。时间复杂度从
优化到了
。
双指针的算法模板比较简单,突破口主要是需要找到题目中的单调性,从而加以利用。
快慢指针
快慢指针一个链表操作技巧,它还有一个有趣的名字,龟兔赛跑。
- 移除元素:
- classSolution{
- public:
- intremoveElement(vector<int>&nums,intval){
- intslowIndex=0;
- for(intfastIndex=0;fastIndex<nums.size();fastIndex++){
- if(val!=nums[fastIndex]){
- nums[slowIndex++]=nums[fastIndex];
- }
- }
- returnslowIndex;
- }
- };
- 环的入口位置:应用快慢指针,快指针走两步,慢指针走一步。假使有环,两指针迟早相遇;假使无环,快指针就会走到尽头,退出循环。如果有环,慢指针重新开始,此时快指针是交点,同速两指针交点必是入口。
- classSolution{
- public:
- ListNode*detectCycle(ListNode*head){
- ListNode*slow=head;
- ListNode*fast=head;
- while(fast&&fast->next){
- fast=fast->next->next;
- slow=slow->next;
- if(fast==slow)break;
- }
- if(fast&&fast->next){
- slow=head;
- while(slow!=fast){
- slow=slow->next;
- fast=fast->next;
- }
- returnslow;
- }
- returnnullptr;
- }
- };
- 链表的中间结点:应用快慢指针,快指针走两步,慢指针走一步。快指针走到尽头时,慢指针刚好走了一半,返回即为中间结点。
- 删除链表的倒数第 N 个结点:快指针先走 n 步,然后快慢指针同时走,快指针走到头时,慢指针就在倒数第 n 个位置。
反向指针
反向指针经典题目是N sum 系列和二分变种题目。
N sum 系列的经典题目是:三数之和

- defthreeSum(nums):
- nums.sort()
- #[-4,-1,-1,0,1,2]
- res_list=[]
- #头部循环查找
- foriinrange(len(nums)):
- #必须判断nums[i]>nums[i-1]这个条件
- ifi==0ornums[i]>nums[i-1]:
- #最左端
- l=i+1
- #最右端
- r=len(nums)-1
- whilel<r:#正在查找
- three_sum=nums[i]+nums[l]+nums[r]
- ifthree_sum==0:
- res_list.append([nums[i],nums[l],nums[r]])
- l+=1#右移一位
- r-=1#左移一位
- whilel<randnums[l]==nums[l-1]:
- #从左往右,相同数值直接跳过
- l+=1
- whiler>landnums[r]==nums[r+1]:
- #从右往左,相同数值直接跳过
- r-=1
- elifthree_sum>0:
- #大于零,右边数值大,左移
- r-=1
- else:
- #小于零,左边数值小,右移
- l+=1
- returnres_list
在四种二分变种中,根据王争算法专栏中,写死low = 0,high = len(list) - 1。循环条件low <= high。往左移动high = mid - 1,往右移动low = mid + 1
- defbinary_search(nums,target):
- '''标准二分算法模板'''
- low=0
- high=len(nums)-1#注意1low和high用于跟踪在其中查找的列表部分
- whilelow<=high:#注意2只要还没有缩小到只有一个元素,就不停的检查
- mid=(low+high)//2
- iflist[mid]==target:
- returnmid
- eliflist[mid]>target:
- high=mid-1#注意3猜的数字大了
- eliflist[mid]<target:
- low=mid+1#注意4猜的数字小了
- returnmid
- defbsearch_low(nums,target):
- '''求第一个等于定值'''
- low=0
- high=len(nums)-1
- #这里需要<=
- whilelow<=high:
- #这里需要注意:就是使用((high-low)>>1)需要双扩号
- mid=low+((high-low)>>1)
- ifnums[mid]<target:
- low=mid+1
- elifnums[mid]>target:
- high=mid-1
- else:
- ifmid==0ornums[mid-1]!=target:
- returnmid
- else:
- high=mid-1
- return-1
- defbsearch_high(nums,target):
- '''求最后一个等于定值的'''
- low=0
- higt=len(nums)-1
- whilelow<=higt:
- mid=low+((higt-low)>>1)
- ifnums[mid]>target:
- higt=mid-1
- elifnums[mid]<target:
- low=mid+1
- else:
- ifmid==(len(nums)-1)ornums[mid]!=nums[mid+1]:
- returnmid
- else:
- low=mid+1
- return-1
- '''
- 查找第一个大于等于给定值的元素
- *如序列:3,4,6,7,19查找第一个大于5的元素,即为6,return2
- *第一个大于给定值,则说明上一个小于给定值,依次判断
- '''
- defbsearch_low_not_less(nums,target):
- low=0
- high=len(nums)-1
- while(low<=high):
- mid=low+((high-low)>>1)
- ifnums[mid]>=target:
- ifmid==0ornums[mid-1]<target:
- returnmid
- else:
- #往左移动
- high=mid-1
- else:
- #往右移动
- low=mid+1
- return-1
- '''
- 查找第一个小于给定值的元素
- *如序列:3,4,6,7,19查找第一个小于5的元素,即为4,返回1
- *第一个大于给定值,则说明上一个小于给定值,依次判断
- '''
- defbsearch_high_not_greater(nums,target):
- '''求最后一个小于等于值'''
- low=0
- higt=len(nums)-1
- whilelow<=higt:
- mid=low+((higt-low)>>1)
- ifnums[mid]<=target:
- if(mid==len(nums)-1)or(nums[mid+1]>target):
- returnmid
- else:
- low=mid+1
- else:
- higt=mid-1
- return-1
滑动窗口
原文:https://mp.weixin.qq.com/s/ioKXTMZufDECBUwRRp3zaA
滑动窗口算法是双指针技巧的最高境界,主要用于两个字符串匹配的问题。
掌握了滑动窗口的解题模板可以轻松解决一系列字符串匹配的问题。
下面模板代码来源labuladong,解决LeetCode 76 题,Minimum Window Substring,求最小覆盖子串。
- /*滑动窗口算法框架*/
- stringminWindow(strings,stringt){
- //两个unordered_map,一个need记录模式串的字符数量,一个window记录窗口的字符
- unordered_map<char,int>need,window;
- //初始化need
- for(charc:t)need[c]++;
- intleft=0,right=0;
- //两个unordered_map的符合条件数目
- intvalid=0;
- //记录最小覆盖子串的起始索引及长度
- intstart=0,len=INT_MAX;
- while(right<s.size()){
- //c是将移入窗口的字符
- charc=s[right];
- //右移窗口
- right++;
- //进行窗口内数据的一系列更新
- if(need.count(c)){
- window[c]++;
- if(window[c]==need[c])
- valid++;
- }
- //判断左侧窗口是否要收缩
- while(valid==need.size()){
- //在这里更新最小覆盖子串
- if(right-left<len){
- start=left;
- len=right-left;
- }
- //d是将移出窗口的字符
- chard=s[left];
- //左移窗口
- left++;
- //进行窗口内数据的一系列更新
- if(need.count(d)){
- if(window[d]==need[d])
- valid--;
- window[d]--;
- }
- }
- }
- //返回最小覆盖子串
- returnlen==INT_MAX?
- "":s.substr(start,len);
- }
在python里unodered map可以用collections.defaultdict和collections.Counter实现
原文链接:https://mp.weixin.qq.com/s/U-lUGtVkLR9i0M4MdwjInQ








发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。