算法训练-双指针

news2024/11/22 17:42:21

双指针

  • 同向双指针
    • 3. 无重复字符的最长子串
    • 209. 长度最小的子数组
    • 713. 乘积小于 K 的子数组
  • 相向双指针
    • 167. 两数之和 II - 输入有序数组
    • 15. 三数之和
    • 438. 找到字符串中所有字母异位词
  • 滑动窗口
    • 接雨水

同向双指针

3. 无重复字符的最长子串

在这里插入图片描述
题目链接

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int ret=0;
        unordered_map<char,int> hashmap;
        for(int i=0,j=0;j<s.size();j++)
        {
            hashmap[s[j]]++;
            while(hashmap[s[j]]>1)//当当前字符的哈希值大于1,说明前面有重复的,
            //要删除,在while里删除,从i位置开始删,直到,当前值的哈希不大于1,删的过程也会把其他字符的哈希--,那是应该的,因为题目要求的是连续不重复子串
            {
                hashmap[s[i]]--;
                i++;
            }
            ret=max(ret,j-i+1);
        }
        return ret;
    }
};

“\n”

209. 长度最小的子数组

在这里插入图片描述
题目链接

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size();
        int minsize=n+1;
        int sum=0;
        for(int i=0,j=0;j<n;j++)//用j进行遍历加
        {
            sum+=nums[j];
            while(sum>=target)//在while里面不断进行sum减少,让其不满足while,同时指针i向后移动
            {
                minsize=min(minsize,j-i+1);
                sum-=nums[i];
                i++;
            } 
        }
        return minsize > n ? 0 : minsize;
    }
};

“\n”

713. 乘积小于 K 的子数组

在这里插入图片描述
题目链接

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        if(k<=1)
        return 0;
        int num=0;
        int mult=1;
        for(int j=0,i=0;j<nums.size();j++)
        {
            mult*=nums[j];
            while(mult>=k)
            {
                mult/=nums[i];
                i++;
            }
            num+=j-i+1;
            //求和 使用符合条件的区间内元素个数
        }
        return num;
    }
};

这三道题都是双指针解决,基本都是一个模子,外循环遍历结点,内循环while判断区间条件,最后出while对区间长度计算,返回结果

相向双指针

167. 两数之和 II - 输入有序数组

在这里插入图片描述
题目链接

这个题还行,能够理解,一有思路就能写出来

class Solution {
public:
//相向双指针:不断缩减区间,每一次都能缩减一个元素
    vector<int> twoSum(vector<int>& numbers, int target) {
        int n=numbers.size();
        vector<int> ret(2);
        for(int i=0,j=n-1;i<j;)
        {
            //要很好的利用到数组升序这个条件,如果不升序,那就将其变为升序,保存原先的下标
            if(numbers[i]+numbers[j]>target)
            {j--;continue;}
            if(numbers[i]+numbers[j]<target)
            {i++;continue;}
            //每次花O(1)时间去删除一个元素,减少元素的个数
            //原先花费O(n)的时间,获取O(1)的信息,即:遍历一遍,只能直到一个数与其他数组合不行
            //现在花费O(1)的时间,获取O(n)的信息,即:知道这个数,和任何其他数都不能组成,直接把区间缩小了
            else 
            {
                ret[0]=i+1;
                ret[1]=j+1;
                return ret;
            }
        }
        return ret;
    }
};

// class Solution {
// public:
//     vector<int> twoSum(vector<int>& numbers, int target) {
//         int n=numbers.size();
//         vector<int> ret(2);
//         for(int i=0;i<n-1;i++)
//         {
//             if(i!=0&&numbers[i]!=0&&numbers[i]==numbers[i-1])continue;
//             for(int j=i+1;j<n;j++)
//             {
//                 if(numbers[j]!=0&&numbers[j]==numbers[j-1])continue;
//                 if(numbers[i]+numbers[j]==target)
//                     {
//                         ret[0]=i+1;
//                         ret[1]=j+1;
//                         return ret;
//                     }
//                     else if(numbers[i]+numbers[j]>target)
//                     break;
//             }
//         }
//         return ret;
//     }
// };

15. 三数之和

在这里插入图片描述
题目链接

能看懂思路,但是写不出来,特判好多,以及何时就应该移动指针。没有想到转换成两数求和

class Solution{
public:
vector<vector<int>> threeSum(vector<int>& nums) 
    {
        int size = nums.size();
        if (size < 3)   return {};          // 特判
        vector<vector<int> >res;            // 保存结果(所有不重复的三元组)
        std::sort(nums.begin(), nums.end());// 排序(默认递增)
        for (int i = 0; i < size; i++)      // 固定第一个数,转化为求两数之和
        {
            if (nums[i] > 0)    return res; // 第一个数大于 0,后面都是递增正数,不可能相加为零了
            // 去重:如果此数已经选取过,跳过
            if (i > 0 && nums[i] == nums[i-1])  continue;
            // 双指针在nums[i]后面的区间中寻找和为0-nums[i]的另外两个数
            int left = i + 1;
            int right = size - 1;
            while (left < right)
            {
                if (nums[left] + nums[right] > -nums[i])
                    right--;    // 两数之和太大,右指针左移
                else if (nums[left] + nums[right] < -nums[i])
                    left++;     // 两数之和太小,左指针右移
                else
                {
                    // 找到一个和为零的三元组,添加到结果中,左右指针内缩,继续寻找
                    res.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    left++;
                    right--;
                    // 去重:第二个数和第三个数也不重复选取
                    // 例如:[-4,1,1,1,2,3,3,3], i=0, left=1, right=5
                    while (left < right && nums[left] == nums[left-1])  left++;
                    while (left < right && nums[right] == nums[right+1])    right--;
                }
            }
        }
        return res;
    }
};

我的想法:排序,先找0,然后从0位置向前向后遍历,找相加=0,之后找一个正数的情况,和一个负数的情况,注意当区间之和大于0或小于0时,剩下的元素就不用判断了,没写完

class Solution {
public:
    //至少有一个负数,除非全是0
    //可能有一个正数或两个,一个正数,也可能有0
    //总结起来:1.有0;2.一个正;3.一个负
    vector<vector<int>> threeSum(vector<int>& nums) {
        int n=nums.size();
        vector<vector<int>> arr;

        vector<int> temp{0,0,0};
        sort(nums.begin(),nums.end());
        int cnt=0;
        for(int i=0;i<n;i++)
        {
            if(0==nums[i])cnt++;
            if(cnt==3)break;
        }
        if(cnt==3)
        arr.push_back(temp);
        
        int zero_pos=-1;
        for(int i=0;i<n;i++)
        {
            if(nums[i]==0)
            {zero_pos=i;break;}
        }
        //0存在,找到0的位置了
        if(zero_pos!=-1)
        {
            int left=zero_pos,right=zero_pos;
            while(left>=0&&right<n)
            {
                for()
            }
        }


        // vector<pair<int,int>> hash;
        // int i=0;
        // for(auto& x:hash)
        // {
        //     x.first=nums[i++];
        //     x.second=i;
        // }
        // sort(hash.begin(),hash.end(),[](const pair<int,int>& p1,const pair<int,int>& p2)
        //                              {return p1.first>p2.first;});
        

    }
};

438. 找到字符串中所有字母异位词

在这里插入图片描述

题目链接

一种经典思路是初始化p的字符数组然后维护数组每个元素不小于0。 开始向右滑动窗口,减去并相应字符,
如果频率小于0就收缩左侧边界直到频率不再小于0。窗口长度与p长度一致时达成条件。


    vector<int> findAnagrams(string s,string p)
    {
        int m=s.size();
        int n=p.size();
        if(m<n)return {};
        vector<int> hs(26);
        for(auto x:p)
            ++hs[x-'a'];
        
        vector<int> ret;
        for(int l=0,r=0;r<m;r++)//滑动窗口为:[l,r],初始窗口为[0,0]
        {
            --hs[s[r]-'a'];
            while(hs[s[r]-'a']<0)//有某一字符的hash为负数,说明此时新加入字符,造成窗口[l,r]内的子串,是不符合p的,因为小于说明某一字符是多的,那么就要while重新调整子串
            {
                ++hs[s[l]-'a'];
                ++l;
                //调整子串从left开始,到right,会越界吗,不会,因为即便是最总也就是窗口内没有字符了,无需越界判断
            }
            if(r-l+1==n)//当窗口大小和p的长度一样,能走到这一步说明,元素组成是相同的,顺序不关心,把left加入ret
                ret.push_back(l);
        }
        return ret;
    }

这一题虽说是滑动窗口,但其实和双指针差不多,可以看到的是在核心的代码也是for遍历内部加while判断

滑动窗口

接雨水

在这里插入图片描述
题目链接
方法一:

    //方法一:
    //求每一个位置的前缀pre最大,和后缀tail最大
    //每一处能存水的多少,就是min(pre,tail)-height[i]要减去当前的柱子高度
    int trap(vector<int>& height) {
        int n=height.size();
        vector<int> pre_arr(n);
        vector<int> tail_arr(n);
        pre_arr[0]=height[0];
        tail_arr[n-1]=height[n-1];
        for(int i=1,j=n-2;i<n;i++,j--)
        {
            pre_arr[i]=max(pre_arr[i-1],height[i]);
            tail_arr[j]=max(height[j],tail_arr[j+1]);
        }
        int sum=0;
        for(int i=0;i<n;i++)
        {
            sum+=(min(pre_arr[i],tail_arr[i])-height[i]);
        }
        return sum;
    }   

方法二:

    //方法2:
    int trap(vector<int>& height)
    {
        int left=0;
        int max_left=height[left];
        int right=height.size()-1;
        int max_right=height[right];

        int sum=0;
        while(left<right)
        {
            //如果左最大 < 右最大,此时肯定是依照左来计算,因为右边即便有更大的,雨水也不会接高于左    
            if(max_left<=max_right)
            {
                sum+=max_left-height[left];
                left++;
                max_left=max(max_left,height[left]);
            }
            //右侧同理
            else 
            {
                sum+=max_right-height[right];
                right--;
                max_right=max(max_right,height[right]);
            }
        }
        return sum;
    }
  1. 盛最多水的容器
    在这里插入图片描述

题目链接

       int maxArea(vector<int>& height) {
        int left=0,right=height.size()-1;
        int max_area=min(height[0],height[right])*right;

        while(left<right)
        {
            int area=(right-left)*min(height[left],height[right]);
            max_area=max(max_area,area);
            if(height[left]<height[right])
            left++;
            else right--;
            //每次只移动一方因为一次只保证了一方的最大,那就移动小的那一边,去找更大的,并且每次移动一步也不会出现,越界问题,不需要在内层在去进行判断
        }
        return max_area;
    }

我的想法:(这是有问题的)
left=0 , right=n-1
从做左开始,肯定要找一个高于left的,右边也一样
left–还是小于最早的left
right也是
那就继续二者都向前,直到有某一个大于

    int maxArea(vector<int>& height) {
        int left=0,right=height.size()-1;
        int max_area=min(height[0],height[right])*right;

        while(left<right)
        {
            int i=left;
            while(i<right&&height[left]>=height[i])
            {
                i++;
            }
            left=i;
            max_area=max(max_area,min(height[left],height[right])*(right-left));
            int j=right;
            while(j>left&&height[right]>=height[j])
                j--;
            right=j;
            max_area=max(max_area,min(height[left],height[right])*(right-left));
        }
        return max_area;
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/532037.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

09——svg中path的使用

一、path 是 svg 中最强大的图形 用于定义一个 路径所有命令均允许小写字母。大写 表示绝对定位&#xff0c;小写 表示 相对定位 &#xff08;相对于上一个结束的坐标&#xff09;d 属性中包含所有路径的点&#xff0c;可根据命令缩写 自由组合 命令 名称 …

阿里云备案服务码是什么?备案服务码申请及限制说明

阿里云备案服务码是什么&#xff1f;ICP备案服务码怎么获取&#xff1f;阿里云备案服务码分为免费和付费两种&#xff0c;申请备案服务码是有限制条件的&#xff0c;需要你的阿里云账号下有可用于申请备案服务码的云产品&#xff0c;如云服务器、建站产品、虚拟主机等&#xff…

【刷题之路Ⅱ】LeetCode 475. 供暖器

【刷题之路Ⅱ】LeetCode 475. 供暖器 一、题目描述二、解题1、方法1——排序后二分法1.1、思路分析1.2、代码实现 2、方法2——排序后双指针2.1、思路分析2.2、代码实现 一、题目描述 原题连接&#xff1a; 475. 供暖器 题目描述&#xff1a; 冬季已经来临。 你的任务是设计一…

怎样能把两张照片拼成一张图片,5种工具分享

怎样能把两张照片拼成一张图片&#xff1f;图片拼合的应用场景是很多的。比如将几张相册中的照片拼成一张合影、将多个地图截图拼合在一起形成一个更大的区域地图、将多个漫画图像合并成一本漫画册等。这项技术可以方便地将多张图片整合为一张&#xff0c;节省时间和精力。 因此…

ThinkPHP6布局的方式之模板布局,全局配置方式,模板标签方式,动态方法布局

ThinkPHP6布局的方式之模板布局 ThinkPHP的模板引擎内置了布局模板功能支持&#xff0c;可以方便的实现模板布局以及布局嵌套功能。 有三种布局模板的支持方式&#xff1a;全局配置方式&#xff0c;模板标签方式&#xff0c;动态方法布局。 第一种方式&#xff1a;全局配置方…

有价值项目分享,缺项目可直接搜索(持续更新中)

​近来统计一下最近发的一些资源&#xff0c;包括CSDNB站微信公众号三个平台&#xff0c;仅包括Java资源&#xff08;SSMSpringBootuniapp&#xff09;、部分硬件、安卓资源&#xff0c;一共30758492588275个&#xff0c;可覆盖95%的毕业题目&#xff0c;大家可在相关归档内获取…

2023 年破解 PDF 密码的 5 种最佳方法

世界越来越依赖数字文档和信息存储。最流行和广泛使用的数字文档文件格式之一是便携式文档格式 (PDF)。PDF 文件用途广泛、可靠&#xff0c;并提供高级别的安全性以保护敏感信息免遭未经授权的访问。保护 PDF 的一种常用方法是通过密码保护。在这篇博文中&#xff0c;我们将讨论…

从SRM到采购供应链,云时通SRM助力东明实现采购数字化再升级!

随着制造业不断向高端跃升&#xff0c;十年来&#xff0c;中国制造企业早已具备全球领先水平。而引领制造业向数字化、网络化、智能化转型升级&#xff0c;是中国智造进一步跨越的关键。 1995年&#xff0c;浙江东明不锈钢制品股份有限公司(以下简称“东明”)成立&#xff0c;作…

超细!从零安装压测工具 jmeter(附JDK下载安装教程,20230516的JDK8最新版)

两步走&#xff0c;安装 JDK 和 jmeter&#xff0c;如果安装了JDK的同志可以直接看第二步。 针对的操作系统&#xff1a;Windows。 下载JDK 官网指路&#xff08;处于稳定性考虑&#xff0c;安装的JDK8&#xff09;&#xff1a; Java Downloads | Oraclehttps://www.oracle.c…

Java配置方式使用Spring MVC

文章目录 基于Java配置方式使用Spring MVC一、创建Maven项目二、添加相关依赖三、创建日志属性文件四、创建首页文件五、创建Spring MVC配置类六、创建Web应用初始化配置类七、创建演示控制器八、配置Tomcat服务器九、启动服务器&#xff0c;查看效果 基于Java配置方式使用Spri…

「计算机网络」HTTP1.0、HTTP1.1和HTTP2.0的演变

「计算机网络」HTTP1.0、HTTP1.1和HTTP2.0的演变 参考&鸣谢 HTTP1.0、HTTP1.1、HTTP2.0的关系和区别 doubleYong 计算机网络_HTTP1.0、HTTP1.1和HTTP2.0的区别 一只前端小马甲 文章目录 「计算机网络」HTTP1.0、HTTP1.1和HTTP2.0的演变一、先说结论二、HTTP网络请求过程三…

【01】一步一步命令行输出VC hello world

一步一步命令行输出VC hello world 安装VS2022编写hello world程序配置cl.exe编译helloworld.cpp总结 安装VS2022 VS2022的安装程序下载地址:https://visualstudio.microsoft.com/zh-hans/downloads/ 。下载完成之后点击程序会进入到选择安装VS2022组件的安装程序&#xff0c;…

小红的好数组陡峭值之和

题目如下 这个题我一开始是先生成满足0&#xff0c;1&#xff0c;2的全排列&#xff0c;但是n很大时很快就超出内存限制了&#xff0c;后来想到用动态规划的方法做&#xff0c;这里先分析一下。 n2时&#xff0c;有01&#xff0c;02&#xff0c;10&#xff0c;12&#xff0c;2…

自动化设备应用之样本手册

Lookbook&#xff0c;新品展示图&#xff0c;是时尚品牌的必备品。Lookbook既展示了新系列&#xff0c;也突出了品牌的基本调性。创建样本手册是释放创造力并从其他时装设计师中脱颖而出的机会。有吸引力的封面、精心策划的图像、精巧的布局、颜色标识和传达风格都是品牌内容传…

建构筑物安全监测

监测要求 1&#xff09;观测点应设置在观测段结构构件的控制断面上&#xff1b; 2&#xff09;平面应力状态的结构应力观测宜设置三向应变观测点,主应力方向明晩的部位可设置单向或两向应变观测点&#xff1b; 3&#xff09;建筑物的重要部位应增设观测点&#xff1b; 4&am…

ControlNet让SD变得可控

ControlNet是一个用于深度神经网络的控制技术&#xff0c;它可以通过操作神经网络块的输入条件来控制神经网络的行为。在这里&#xff0c;“网络块”是指常用的神经层集合&#xff0c;例如“resnet”块、“conv-bn-relu”块、多头注意力块等。通过克隆神经网络块的参数并应用零…

软考A计划-真题-分类精讲汇总-第十七章(数据结构与算法)

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

智慧档案馆建设之八防十防常用的设备

档案八防十防常用的十款设备 序号 名称 1 温湿度传感器 2 空气质量云测仪 3 恒湿净化一体机 4 健康防护一体机 5 综合智能触摸一体化区域控制器 6 空调红外学习控制模块 7 漏水检测控制器及感应线 8 数字烟雾传感器 9 红外防盗传感器 10 系统软件平台 附…

redis高级篇(1)

分布式缓存 单节点redis的问题: 1)数据丢失的问题&#xff0c;redis是基于内存来进行存储的&#xff0c;当服务器重启的时候可能会丢失数据 2)无法满足高并发场景 3)如果redis宕机&#xff0c;那么这个服务不可用&#xff0c;所以就需要有一种自动的故障恢复手段&#xff0c;必…

从裸机启动开始运行一个C++程序(一)

前言 对于一个C程序员来说&#xff0c;可能更多是是每天都在跟各种上层语义、设计模式、软件方法等等在打交道。但对于「一个C程序是如何运行在机器上的」这件事可能会比较陌生。有时&#xff0c;遇到一些问题&#xff0c;在宏观角度看起来可能比较难以解释&#xff0c;但其实…