算法学习日记 | 双指针

🧠 算法学习日记 | 今天我用「双指针」解了三道题,原来"左右夹击"能这么高效!

大家好,我是你们的算法学习搭子 👋

今天继续我的算法入门之旅,重点练习了**双指针(Two Pointers)**这一高效的数据遍历技巧。

很多人觉得"双指针"只是用来判断回文的工具,但其实,它是一种空间换时间、动态调整窗口 的经典思想。

我们用两个指针同时从两端或前后移动,避免重复计算,大幅提升效率。

今天我完整做了三道题,每一道都坚持用最朴素的双指针逻辑实现。下面我把题目原文我的原始代码原封不动贴出来,不做任何删减或美化,只为真实记录学习过程。


🔹 题目一:回文判定

题目描述

给定一个长度为 n 的字符串 S 。请你判断字符串 S 是否是回文。
输入描述

输入仅 1 行包含一个字符串 S

1 \\leq \|S\| \\leq 10\^6 ,保证 S 只包含大小写、字母。
输出描述

若字符串 S 为回文串,则输出 Y,否则输出 N
输入输出样例

复制代码
示例 1
输入
abcba
输出
Y

示例 2
输入
abcbb
输出
N

✅ 我的代码(完全保留原始写法)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1e6+5;
char s[N];

int main()
{
    cin>>s+1;
    int n = strlen(s+1);
    int l=1;
    int r=n;
    int flag =1;
    while(l<r){
        if(s[l]!=s[r]){
            flag=0;
            break;
        }
        ++l;
        --r;
    }
    if(flag)cout<<"Y";
    else cout<<"N";
    return 0;
}

🔹 题目二:美丽的区间

题目描述

给定一个长度为 n 的序列 a_1, a_2, \\ldots, a_n 和一个常数 S

对于一个连续区间,如果它的区间和大于或等于 S ,则称它为美丽的区间。

对于一个美丽的区间,如果其区间长度越短,它就越美丽。

请你从序列中找出最美丽的区间。

输入描述

第一行包含两个整数 n, S ,其含义如题所述。

接下来一行包含 n 个整数,分别表示 a_1, a_2, \\ldots, a_n

约束: 10 \\leq N \\leq 10\^5 ,,, 1 \\leq a_i \\leq 10\^4 ,,, 1 \\leq S \\leq 10\^8

输出描述

输出共一行,包含一个整数,表示最美丽的区间的长度。

若不存在任何美丽的区间,则输出 0。
输入输出样例

复制代码
示例 1
输入
5 6
1 2 3 4 5
输出
2

✅ 我的代码(完全保留原始写法)

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5+5;
int a[N];

int main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int n,s;
    cin>>n>>s;
    int sum=0;
    int ans = n+1;
    for(int i=1;i<=n;++i)cin>>a[i];
    for(int l=1,r=0;l<=n;++l){
        while(l>r || (r+1<=n && sum<s)){
            r++;
            sum+=a[r];
        }
        if(sum>=s){
            ans = min(ans,r-l+1);
        }
        sum-=a[l];
    }
    cout<<(ans > n ? 0 : ans);
    return 0;
}

🔹 题目三:挑选子串

题目描述

n 个数,和一个整数 m

现要从这 n 个数选出一个连续子串,要求这个子串里面至少有 k 个数要大于等于 m

问一共能选出多少个子串(显然子串长度要大于等于 k )。

输入描述

输入第一行是 3 个整数 n, m, k

输入第二行是 n 个整数 a_1, a_2, \\ldots, a_n ,表示序列。

约束: 2 \\leq n \\leq 2000 ,,, 1 \\leq k \\leq \\frac{n}{2} ,,, 1 \\leq m, a_i \\leq 10\^9

输出描述

输出一个整数表示答案。
输入输出样例

复制代码
示例
输入
7 4 2
4 2 7 6 5 1
输出
18

运行限制

  • 最大运行时间:1s
  • 最大运行内存:256M

✅ 我的代码(完全保留原始写法)

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;

const int N=2e3+5;
int a[N];

int main(){
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=1;i<=n;++i)cin>>a[i];
    int ans=0;
    for(int l=1,r=0,cnt=0;l<=n;++l){
        while(l>r || (r<n-1 && cnt < k)){
            cnt += (a[++r] >= m);
        }
        if(cnt >= k) ans += n-r+1;
        cnt -= (a[l]>=m);
    }
    cout << ans <<endl;
    return 0;
}

🌟 我的思考

这三道题虽然形式各异,但都用了双指针的核心思想

  • 回文判定:左指针从头开始,右指针从尾开始,向中间靠拢
  • 美丽的区间:滑动窗口,左指针固定时扩展右指针,找到满足条件后收缩左指针
  • 挑选子串:同样滑动窗口,统计满足条件的元素个数,当满足后累加所有可能的右端点

你会发现:

双指针的本质是"动态窗口" ------ 用两个指针维护一个区间,根据条件决定移动哪个指针。

而且,双指针可以分为两类:

  1. 对撞指针(如回文):从两端向中间移动
  2. 滑动窗口(如后两题):一个指针扩展,另一个指针收缩

✅ 总结

  • 双指针适用于:有序数组、连续子数组、区间问题
  • 常见技巧:排序 + 双指针、滑动窗口、左右夹击
  • 时间复杂度:通常为 O(n) ,远优于暴力枚举
  • 关键在于:明确两个指针的移动条件(何时增,何时减)
  • 不是所有问题都能用双指针解决,需结合具体场景

相关推荐
MobotStone17 小时前
我的 AI 代码清理方法论:从原型到生产,只需 5 步
算法·程序员·架构
沐苏瑶1 天前
Java 搜索型数据结构全解:二叉搜索树、Map/Set 体系与哈希表
java·数据结构·算法
لا معنى له1 天前
WAM与AC-WM:具身智能时代的世界动作模型与动作条件世界模型
人工智能·笔记·学习
ZoeJoy81 天前
算法筑基(二):搜索算法——从线性查找到图搜索,精准定位数据
算法·哈希算法·图搜索算法
Alicx.1 天前
dfs由易到难
算法·蓝桥杯·宽度优先
桦01 天前
【C++复习】:继承
开发语言·c++
_日拱一卒1 天前
LeetCode:找到字符串中的所有字母异位词
算法·leetcode
鱼难终1 天前
类和对象(下)
c++
云泽8081 天前
深入 AVL 树:原理剖析、旋转算法与性能评估
数据结构·c++·算法
薛先生_0991 天前
js学习语法第一天
开发语言·javascript·学习