算法入门之双指针

前言

双指针是针对于有顺序的数据结构一种方法和技巧,通常用于线性的数据结构中,如链表和数组有时也会用在图算法中。

1.碰撞指针

1.1应用 概念

碰撞指针分为左右两个指针,从左右两方按照各自的刷新规则向中间靠拢遍历。遍历链表或者数组。
碰撞指针经常见于二分法中 。
在这里插入图片描述

1.2案例分析(leetcode 35题)

题目:
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。题目链接

示例1:
输入: nums = [1,3,5,6], target = 5
输出: 2

示例2:
输入: nums = [1,2,3,4,5,6,7,8,9], target = 8
输出: 7

解题思路:
在这里插入图片描述

代码:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target)
     {
         int mid,left=0,right=nums.size()-1;//初始起始,中点值
         while(left<=right)//当左右指针相等的时候证明数组已经遍历完了。
         {
             mid=left+(right-left)/2;
             if(target==nums[mid])
             {return mid;}
             else if(target>nums[mid])
             {left=mid+1;}
             else
             {right=mid-1;}
         };
         return right+1;
         
    };
};

2.快慢指针

2.1 应用 概念

在这里插入图片描述

  • 计算链表的中点:
    快慢指针从头节点出发,每轮迭代中,快指针向前移动两个节点,慢指针向前移动一个节点,最终当快指针到达终点的时候,慢指针刚好在中间的节点。
  • 求链表倒数第k个元素:
    设定快慢两个指针,让其中快指针先走k步,然后快慢指针以相同的速度移动,当快指针到达终点,则慢指针正好位于倒数第k个元素。
  • 判断链表是否有环
    使用快慢指针,当链表中存在环时,两个指针最终会在环中相遇。
  • 判断链表中环的起点:
  • 求链表中环的长度:
    只要相遇后一个不动,另一个前进直到下一次相遇算一下走了多少步就好了

2.2 案例分析(leetcode 19题)

题目:
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。题目链接

示例1:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例2:
输入:head = [1], n = 1
输出:[]

解题思路如下:
这里头部引入哑节点,是为了让头节点变成普通节点。

操作示意图
代码:

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n)
    {
        ListNode* fast=head;
        ListNode* slow;
        ListNode* temp=new ListNode(0,head);//引进哑节点,因为想把头节点这个特殊的节点当成一个普通节点来看。
        slow=temp;
        int i=0;
        while(i<n)
        {
            fast=fast->next;
            i++;
        }//让快指针先领先n个位置
        while(fast)
        {
        
             fast=fast->next;
             slow=slow->next;
        }
         slow->next=slow->next->next;//当快指针到达链表末尾时候,让慢指针指向下下一个地址(即删除下一位)
    
        return temp->next;//删除增加的0头,从后面一位开始读取,temp->next是一个地址,指向slow的头地址。
        delete temp;

    }
};


3.滑动窗口法

3.1 概念

滑动窗口法:可以理解为用两个指针作为窗口的左右框。每当右端指针扩展,窗口就会更新,每次的新窗口都需要判断是否还是满足要求的窗口,如果不是满足要求的窗口需要对窗口左端进行裁剪(即左指针指向下一个值)。

在这里插入图片描述

3.2 案例分析 <leetcode 3题 >

无重复字符的最长子串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。题目链接

示例1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

示例2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。

解题方法:
流程框图如下:

在这里插入图片描述
代码:

class Solution {
public:
       int lengthOfLongestSubstring(string s) 
       
       {
           int start=0,end=0,result=0,length=0;
           int n=s.size();
           while(end<n)//判断是否到字符串的结尾
           {
              char temp=s[end];//把新加入的字符设置为标志位
              //判断新加入的字符在原字符串里面有没有。
               for( int index=start;index<end;index++)//index=end的话窗口不能滑动起来。
               {
                   if(s[index]==temp)//如果发现第index个字符与新加入的字符相同
                   {
                       //开始滑动窗口

                       start=index+1;//让起始点变成这个index+1,为了满足题目要求
                       length=(end-start);//刷新length长度

                       break;
                   }   
               }
               length++;//如果加入
               end++;//无论重不重复都要end+1;
               result=max(length,result);
           }
               return result;
       }
};

ps:算法萌新,有错误还望指正 谢谢阅读。


4. 参考文献

  1. https://leetcode-cn.com/problems/remove-nth-node-from-end-of-list/solution/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-b-61/
  2. https://zhuanlan.zhihu.com/p/95747836
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值