【蓝桥杯算法】---第四讲---双指针

文章目录

        • 概念
        • 对撞指针
        • 快慢指针
        • 双数组指针
        • 题目练习

概念

双指针算法是一种非常常用的算法,是对暴力算法的一种优化,其实现原理也非常简单且灵活,具体操作一般是定义两个指针对数组进行遍历等操作。
双指针算法有很多种情况,如下:
一.对撞指针(头尾指针)
头指针指向数组的第一个数字,尾指针指向数组的最后一个数字。
【蓝桥杯算法】---第四讲---双指针_第1张图片
二.单数组同向指针(快慢指针)
两个指针指向同一个数组的第一个数字或者最后一个数字,一个指针走的快,一个指针走的慢。
【蓝桥杯算法】---第四讲---双指针_第2张图片
三.双数组指针
这种情况多是两个指针分别指向两个不同的数组,分别进行遍历。
【蓝桥杯算法】---第四讲---双指针_第3张图片

对撞指针

题目链接167. 两数之和 II - 输入有序数组
【蓝桥杯算法】---第四讲---双指针_第4张图片
主要思路:设置头指针left和尾指针right。通过两个指针遍历找到目标数字。

分析:为什么这题需要用头尾指针?
假设该题使用两个指针同时指向数组的第一个数字。但是这样就会导致很难实现。
关于使用头尾指针
题目要求是在数组中找到两个数字的和==target。而定义头尾指针非常适合该题。这就像定义了一个规定长度的窗口,头指针+尾指针指向的数字之和=窗口值。通过改变窗口值来寻找匹对的target。

题解:
1. 初始化操作:一个left头指针,一个right尾指针

2. 设定初始的窗口值sum=头指针指向的数字+尾指针指向的数字

3. 通过窗口值与target的比较,对窗口的长度进行修改。因为该数列是一个递增数列,所以left指针向前走就会导致窗口值变大,right指针后退就会导致窗口值变小。

4. 最终遍历完成,left指针和right指针指向的数字就是最终答案

5. 这里的最终答案需要+1,因为数组是从0开始存储的,但是题目要求的是从1开始。

class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        vector<int> v3;
        int left=0;//(1)
        int right=numbers.size()-1;//(2)
        int sum;
        sum=numbers[left]+numbers[right];//(3)
        while(left<right){
            if(sum==target)//(4)
            break;
            else if(sum<target){//(5)
                sum-=numbers[left++];
                sum+=numbers[left];
            }
            else if(sum>target){//(6)
                sum-=numbers[right--];
                sum+=numbers[right];
            }
        }
        v3.push_back(left+1);
        v3.push_back(right+1);
        return v3;


    }
};

(1):创建头指针
(2):创建尾指针
(3):设置初始的窗口值
(4):窗口值==target,说明找到了答案,退出循环
(5):窗口值小于target,说明需要扩大窗口,让头指针前进
(6):窗口值大于target,说明需要缩小窗口,让尾指针后退

快慢指针

题目链接剑指 Offer 48. 最长不含重复字符的子字符串
【蓝桥杯算法】---第四讲---双指针_第5张图片
主要思路: 设置两个快慢指针分别指向数组的第一个元素,用一个辅助数组计算不同字符出现的次数。

题解:
1.初始化操作: 设置一个快指针i和慢指针j同时指向数组的第一个元素,一个数字全是0的辅助数组a[N]

辅助数组a[N]的作用:用于记录字符出现的次数,如a字符出现,那么辅助数组a[‘a’]这个位置的值就+1.当辅助数组某个位置的值出现两次时,就说明这个字符连续出现了两次。

2. 快指针i先走,i指针每走一步,辅助数组就将当前字符asall码位置的数字+1,表示这个字符出现了一次

3. 当相同的字符出现两次以后,慢指针会一直走到快指针的位置

4. 对当前出现的最长连续不重复子串进行更新。

const int N=40000;

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
    int a[N]={0};
    int res=0;
    int j=0;
    for(int i=0;i<s.size();i++){
        a[s[i]]++;//(1)
        while(a[s[i]]>1){//(2)
            a[s[j]]--;
            j++;
        }
        res=max(res,i-j+1);//(3)
        
    }
    return res;
    }
};

(1):使用辅助数组存储当前字符的出现次数
(2):碰到重复字符,慢指针走到快指针位置
(3):更新当前的字符最优长度

双数组指针

题目链接判断子序列
【蓝桥杯算法】---第四讲---双指针_第6张图片
主要思路:设置两个指针分别指向两个数组。

题解:
1. 初始化操作,设置两个指针i和j,i指针指向子串,j指针指向主串

2. 通过j指针遍历主串,当i指针指向的字符和j指针指向的字符相当时,i指针就向前走一步,最后遍历结束,判断i的大小是否等于主串的长度(如果i==主串的长度,说明字串的所有字符均在主串中出现过)。如果i的大小不等于字串的长度,说明该子串不属于该主串。

class Solution {
public:
    
    bool isSubsequence(string s, string t) {
         int i;
    int j;
    for(i=0, j=0;j<t.size();j++){//(1)
        if(s[i]==t[j])//(2)
        i++;
    }
    if(i==s.size()){//(3)
        return true;
    }
    else
   return false;//(4)
    }
};

(1):通过i指针遍历主串
(2):i指针当前指向子串的字符==主串的字符,i指针向前走一步
(3):i的大小等于子串的长度,说明子串属于主串
(4):反之说明子串不属于主串。

题目练习

1.判断子序列
2.167. 两数之和 II - 输入有序数组
3.剑指 Offer 48. 最长不含重复字符的子字符串
4.4297. 截断数组
5.剑指 Offer 57 - II. 和为s的连续正数序列

你可能感兴趣的:(蓝桥杯算法从0到1,算法,蓝桥杯)