当前位置: 首页 > article >正文

双指针算法(快慢指针/对撞指针法)

目录

一、27. 移除元素 - 力扣(LeetCode)

二、双指针算法📌

三、其他题目(见得题多了,一眼就知道用双指针优化)

(1)替换数字 -卡玛网 (不用额外的辅助空间)

(2)空格分割字符串

(3)AcWing 799. 最长连续不重复子序列 - AcWing 【滑动窗口】

 (4)800. 数组元素的目标和 - AcWing==

(5)2816. 判断子序列 


一、27. 移除元素 - 力扣(LeetCode)

数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖 ,这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

二、双指针算法📌

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作

        双指针指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。最常见的双指针算法有两种:一种是,在一个序列里边,用两个指针维护一段区间;另一种是,在两个序列里边,一个指针指向其中一个序列,另外一个指针指向另外一个序列,来维护某种次序。双指针算法的核心思想(作用):优化            -----双指针算法-CSDN博客

 定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

        双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。

先看下本题代码:(本题简单的不形)

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slow=0;
        for(int fast=0;fast<nums.size();fast++)
        {
            if(nums[fast]!=val) 
                nums[slow++]=nums[fast];
        }
        return slow;
        
    }
};

三、其他题目(见得题多了,一眼就知道用双指针优化)

(1)替换数字 -卡玛网 (不用额外的辅助空间)

        https://kamacoder.com/problempage.php?pid=1064

有点is ,挺有趣的一道题目        数组填充类的问题,先预先给数组扩容带填充后的大小,然后在从后向前进行操作;

  1. 不用申请新数组。
  2. 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。
#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    cin>>s;
    int cnt=0;//统计数字的个数
    for(int i=0;i<s.length();i++) 
    {
        if(s[i]>='0'&&s[i]<='9') cnt++;
    }
    //扩容:扩充字符串s的大小,也就是将每个数字替换成"number"之后的大小
    int fast = s.length() - 1;  // 原始字符串的最后一个字符
    s.resize(s.size()+cnt*5);
    //从后往前替换
    int slow=s.size()-1;
    for(;fast>=0;fast--)
    {
        if(s[fast]>='0'&&s[fast]<='9')//替换
        {
            s[slow--]='r';
            s[slow--]='e';
            s[slow--]='b';
            s[slow--]='m';
            s[slow--]='u';
            s[slow--]='n';
        }
        else //不是数字
            s[slow--]=s[fast];
    }

    cout<<s;
return 0;
}

(2)空格分割字符串

int main() {
    string str;
    getline(cin, str);
    
    for (int slow = 0; slow < str.size(); slow++) {
        int fast = slow;
        // 找到第一个空格或到达字符串末尾
        while (fast < str.size() && str[fast] != ' ') {
            fast++;
        }

        // 输出当前单词的每个字符
        for (int k = slow; k < fast; k++) {
            cout << str[k] << endl;
        }
        // 更新 slow 跳到下一个单词的开始位置
        slow = fast;
     
    }

    return 0;
}

 (3)AcWing 799. 最长连续不重复子序列 - AcWing 【滑动窗口】

滑动窗口算法 : 使用两个指针(slowfast)来控制窗口的左右边界​​​​​​​       AcWing 154. 滑动窗口-CSDN博客 (之前刷过的一道滑动窗口的题)

  1. 初始化两个指针:slowfast,都从数组的开始位置出发。

  2. fast 指针逐渐向右扩展窗口,将当前元素 a[fast] 加入到窗口中,并记录该元素的出现次数。

  3. 如果当前元素重复(即 a[fast] 在窗口中已经出现过),则移动 slow 指针,直到窗口内没有重复元素。每移动一次 slow,就减少其对应元素的计数。

  4. 在每一步,计算窗口的大小(即 fast - slow + 1),并更新结果 res,保持记录最大长度的值。

题目还是比较难想的········

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N], s[N];

int main() {
    int n;
    int res = 0;
    cin >> n;

    for (int i = 0; i < n; i++) cin >> a[i];
    // 滑动窗口
    for (int slow = 0, fast = 0; fast < n; fast++) {
        s[a[fast]]++;  // 记录当前元素的出现次数
        // 当出现重复元素时,移动slow指针
        while (s[a[fast]] >1) {  // 重复元素出现
            s[a[slow]]--;  // 减少当前slow指针位置的元素计数
            slow++;  // 移动slow指针,直到没有重复元素
        }
        // 计算当前窗口的长度,更新结果
        res = max(res, fast - slow + 1);
    }
    cout << res << endl;
    return 0;
}

 ​​​​​​​(4)800. 数组元素的目标和 - AcWing==

 挺简单的,巧妙用到升序排列的条件

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
int main()
{
    //在B数组中找等于x-a的tar
    //升序排序的,所以j 从数组 b[] 的尾部开始往前移动(即递减),
        //如果 a[i] + b[j] > x,则继续移动 j,直到a[i] + b[j] == x
    //指针1遍历A数组,指针2在B数组中找
    int n,m,x;
    cin>>n>>m>>x;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<m;i++) cin>>b[i];
    for(int i=0,j=m-1;i<n;i++)
    {
        while(j>=0&&a[i]+b[j]>x) j--;
        if(j>=0&&a[i]+b[j]==x) cout<<i<<" "<<j;
        
    }
    return 0;
}

(5)2816. 判断子序列 

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N],b[N];
// a是b的子序列嘛?
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=0;i<n;i++) cin>>a[i];
    for(int i=0;i<m;i++) cin>>b[i];
    int j=0;//用于在a数组上移动
    for(int i=0;i<m;i++) //遍历b
    {
        
        if(j<n&&b[i]==a[j]) // 找到一个
        {
            j++; // 找下一个
            //cout<<j;
          
        }
    }
    if(j==n) cout<<"Yes"; //全都找到了
    else cout<<"No";
    return 0;
}

是有点弱智的


http://www.kler.cn/a/614705.html

相关文章:

  • coding ability 展开第七幕(前缀和算法——进阶巩固)超详细!!!!
  • RPCGC阅读
  • 媒体直播的力量:解锁新时代传播密码,引爆传播效应,媒介盒子分享
  • SpringCould微服务架构之Docker(5)
  • 大数据Spark(五十五):Spark框架及特点
  • Unity程序嵌入Qt后点击UI按钮Button没有反应
  • Nmap全脚本使用指南!NSE脚本全详细教程!Kali Linux教程!(二)
  • Redis场景问题2:缓存击穿
  • 20组电影美学RED摄像摄影机视频胶片模拟色彩分级调色LUT预设包 Pixflow – CL – RED Camera LUTs
  • Lambda 表达式调试实践指南
  • 笔记:遇见未来——6G协同创新技术研讨会
  • 家乡旅游景点小程序(源码+部署教程)
  • 【数电】半导体存储电路
  • TCP 协议深度解析
  • 代购系统:架构设计、功能实现与用户界面优化
  • 用LLama factory时报类似Process 2504721 got signal: 1的解决方法
  • 基于74LS192的十进制两位数正向计时器(proteus仿真)
  • 鸿蒙项目源码-购物商城v2.0-原创!原创!原创!
  • 【Basys3】外设-灯和数码管
  • Agent中的MCP