“双指针”算法下篇

news2024/9/22 5:31:14

WeChat_20240806081335


 对双指针这一思想在OJ 里面的相关应用,感兴趣的友友们,可以看下此篇博客

https://blog.csdn.net/X_do_myself/article/details/141291451?spm=1001.2014.3001.5502

目录
一·盛最多水的容器
1·题目链接:盛最多水的容器

2· 分析

1)解法一 : 暴力求解

就是逐一进行判断,找出乘积相乘最大的:比如说第一个元素与第二个元素进行结合得出 1* 1 = 1

第一个元素与第三个元素进行结合得出 1*2 = 2……经过一轮的循环,最终得出这一轮乘积最大的

是1*8 = 8

接下来进行第二轮的循环:第二个元素与第三个元素结合,与第四个元素结合……

最终经过几轮循环得出最大乘积:49,即为所求。

对应时间复杂度O(N^2)

 但是这并不是一个优解的算法

2)解法二 :双指针

这个双指针代表的意义:表示一个 范围:所有边界位置的一个范围

3· 算法原理

1)先假设当前左右指针所在位置对应的得出的体积是 V 

2)比较此时 left 和 right 所对应的元素大小,让指向元素小的指针进行移动

3)此时left ,right 指向的位置可以再次得出一个体积,与之前所得出的 V 进行比较,取最大者即

可,重复上述过程,直至left ,right  指针相遇

4)注意细节处理:计算体积之前,需要先求出 2指针所指向元素最小的是哪一个

4· OJ代码
class Solution {
public:
    int maxArea(vector<int>& height) 
    {
        int n = height.size();
        int left = 0,right = n-1;
        int v = 0;
        while(left < right)
        {
            int ret = min(height[left],height[right]) * (right-left);
            v = max(v,ret);
            //代码核心
            // 找高度最小的
            if(height[left] > height[right] )
            right--;
            else
            ++left;
        }
        return v;
    }
};
二·找出和为 s 的两个数
1·题目链接 两数之和
2· 分析

解法一:暴力枚举

对于这个思想,想必各位都不陌生吧,直接2个  for 循环,判断nums[left]  + num[right] 是否为

target 即可

时间复杂度:O(N^2)

解法二:双指针

针对暴力枚举,我们还可以进行优化:

定义2个指针 :left ,right 

3· 算法原理

1) 排序(注意:不要直接对原始数组进行变动)

2)指针移动

初始化:left = 0,right = n-1(n: 数组大小)

num[left] + num[right] > target ,right --: 因为此时是一个有序的数组,num[left]  <=  num[right] 一定

是成立的,当num[left] + num[right] > target  的时候就需要缩小数据范围,进行左移

num[left] + num[right]  <  target ,left++:   同理,一个 有序的数组,num[left] + num[right]  < target ,

此时就需要增大数据,右移

num[left] + num[right] = target :记录此时的元素数值

3)把当前 num[left]  num[right] 进行保存一下

4) 遍历原始数组,找到指定元素之后,返回对应的元素下标

注意此时不能一次性就把 num[left] num[right]遍历完

4· OJ代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) 
    {
        vector<int> ret;
        vector<int> tmp(nums.begin(),nums.end());
        int f1 = 0,f2 = 0;
        //1.排序
        sort(tmp.begin(),tmp.end());
        //2. 双指针
        int left = 0;
        int right = nums.size()-1;
        while(left < right)
        {
            if(tmp[left]+ tmp[right] > target)
            --right;
            else if(tmp[left]+ tmp[right] == target)
            {
                  f1 = tmp[left];
                  f2 = tmp[right];
                   break;
            }
            else
            ++left;

        }
       for(int i = 0;i<nums.size();i++)
       {
        if(nums[i] == f1)
       
       {
         ret.push_back(i);
         break;
       }
       }
        for(int i = 0;i<nums.size();i++)
       {
        if(i != ret[0] && nums[i] == f2)
        {
            ret.push_back(i);
            break;
        }
       }
        return ret;
    }
};
三·有效的三角形个数
1·题目链接  有效的三角形个数
2· 分析

构成三角形的条件:

任意的两边之和都大于第三边  或者是  任意的两边之差都小于第三边

解法一:暴力枚举

三层循环,假设第一次对应数为 a , b ,c

只需要判断 a+b > c,a+c > b, b+c > c 这三个条件是否同时满足即可。

对应时间复杂度 :O(N^3)

解法二:双指针

假设此时固定一个最大的数,只需要在最大的数左区间里面找出 两个数 a+b > 最大的数即可

不知道看到这,各位是否已经有了思路?

 此时问题就已经简化成了:找两数之和大于 S 的问题

这不就是上面找出两数之和为S 的一个变形嘛。

3· 算法原理

我们知道   a<=   b   <=  c  ,一定满足  a+ b > c  这个条件,此时,a,b ,c 这个组合移动可以构成有

效的三角形。

 1)先进行排序

2)从右向左依次固定一个最大的数

3) 指针移动

当 num[left] + num[right ] > c , 此时就是对应的 right - left  j就是这一轮匹配到的个数,同时right 

指针向左移动

因为此时数组是有序的,num[right ] 必定是大于或者等于 num[left ] ,right  向左移动是缩小 

num[left] + num[right ] 的范围

num[left] +num[right ] <= c,left 指针向右移动 : 此时 num[left] 小于或者等于 num[right] ,需要找

下一个匹配的组合,只能left ++ 

草图分析:

 

 

4· OJ代码
class Solution {
public:
    int triangleNumber(vector<int>& nums) 
    {
        //排序
        sort(nums.begin(),nums.end());
        int ret = 0;
        int n  = nums.size();
        //依次固定最大的数
        for(int max_i = n-1;max_i >= 2 ;--max_i)
        {
            int left = 0,right = max_i-1;//注意更新依次max_i,左右指针都要进行改变,所有不能定义在外面
            while(left < right)
            {
                if(nums[left] +nums[right]> nums[max_i])
               {
                 
                 ret += right-left;
                 right--;
               }
                else // <= max_i ,对当前指向的数据扩大
                ++left;
            }
        }
        return ret;

    }
};

 四· 三数之和

1. 题目链接  三数之和
2. 分析
解法一:暴力枚举

3个 for 循环,依次判断 所得之是否为0 即可

对应的伪代码

    for (int i = 0; i < n - 2; ++i)
	{
		for (int j = i + 1; j < n - 1; ++j)
		{
			for (int k = j + 1; k < n; ++k)
			{
				if(num[i]+num[j]+num[k] == 0)
			}
		}
	}

 

细节处理:题目要求三元组不能重复 

时间复杂度:O (N^3) 

前面我们做过两数之和,其实此题就是上面的变形

解法二:双指针结合单调性

3. 算法原理

为了下面描述方便:假设这三个数分别对应 a, b ,c

1) 排序

2)先固定一个数 a , 接下来只需要在 数a 的右边区间找到 b + c = target - a 的两个数

3)指针移动

当 num[left] + num[right] > target -a ,right -- :依然是借助单调性

注意right  再向左移动的过程中,可能会遇到重复的数据 ,需要进行去重的处理

当 num[left] + num[right]  < target-a ,left++:

注意left  再向y右移动的过程中,可能会遇到重复的数据 ,需要进行去重的处理

当 num[left] + num[right]  ==  target-a ,此时把对应的 数据放到一个变量里面,继续进行查找

4) 当left right,相遇的时候,就对a  进行更新,依然注意去重的处理 

4. OJ代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> ret;
        int  n = nums.size();
        //1. 排序
        sort(nums.begin(),nums.end());
        // 2. 双指针结合单调性
        for(int i = 0; i < n-2 && nums[i] <= 0;)
        {
            int left = i+1,right = n-1;
            while(left < right)
            {
                if(nums[left] + nums[right] == -nums[i])
                {
                    ret.push_back({nums[i],nums[left],nums[right]});
                    --right;
                    //去重
                    while(left < right && nums[right] == nums[right+1] )
                    {
                        --right;
                    }
                }
                else if (nums[left] + nums[right] < -nums[i])
                {
                    ++left;
                    //去重
                    while(left < right && nums[left] == nums[left-1])
                    {
                        ++left;
                    }
                }
                else  // (nums[left] + nums[right] > -nums[i])
                {
                  --right;
                    //去重
                    while(left < right && nums[right] == nums[right+1] )
                    {
                        --right;
                    }   
                }
            }
            ++i;
            //去重
            while(i < n-2 && nums[i] == nums[i-1])
            {
                ++i;
            }
        }
        return ret;
    }
};

 五· 四数之和

1. 题目链接  四数之和

2. 分析

想必各位看到这里,应该自认为小case ,这不就是轻松拿捏嘛。双指针走起

解法一:暴力枚举

解法二:双指针结合单调性

这里分析的思路和上面的找三数之和是一样滴

3. 算法原理

1)排序

2)依次固定 2个数,借助循环

3)指针移动

4)去重问题

这里不仅仅涉及到left ,right 去重,还有在固定2个数的时候也需要去重

5)注意数据的溢出

在我们提交代码的时候发现一下报错:

此报错的意思:有符号数据的溢出问题 

解决:

此时只需把int 改为long 即可 

4. OJ代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        vector<vector<int>> ret;
        //排序
        sort(nums.begin(),nums.end());
       
        int n = nums.size();
        //先依次枚举第一个数
        for(int n1 = 0;n1 < n-3; )
        {
            //依次枚举第二个数
            for(int n2 = n1+1;n2 < n-2 ; )
            {
                 //双指针+单调性  
                 //注意溢出问题
                 //超出int范围
               long add =(long) target-(long)nums[n1]-(long)nums[n2];
            // int add = target-nums[n1]-nums[n2];
                int left = n2+1,right = n-1;
                while(left < right)
                {
                    if(nums[left] + nums[right] ==add )
                    {
                        ret.push_back({nums[n1],nums[n2],nums[left],nums[right]});
                        --right;
                        //去重
                        while(left < right && nums[right] == nums[right+1])
                        {
                            --right;
                        }
                    }
                    else if(nums[left] + nums[right]  > add )
                    {
                        --right;
                        //去重
                        while(left < right && nums[right] == nums[right+1])
                        {
                            --right;
                        }
                    }
                    else  // (nums[left] + nums[right] < add )
                    {
                        ++left;
                        while(left < right && nums[left] == nums[left-1])
                        {
                            ++left;
                        }
                    }
                }
                ++n2;
                //去重
                while(n2 < n-2  && nums[n2] == nums[n2-1])
                {
                    ++n2;
                }
            }
            //去重
            ++ n1;
            while(n1 < n-3 && nums[n1] == nums[n1-1])
            {
                ++n1;
            }
        }
        return ret;
    }
};

结语:

对于双指针的思想,我们可以通过以上OJ 题总结一下。当题目要求我们进行一些操作之后,会对

数组分成3部分区间:[0,left-1] [left right ] [right+1, n-1]  ,多数都是“原地”对数组进行操作,此时

可以借助双指针的思想,注意指针的移动,下标的确定

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

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

相关文章

EmguCV学习笔记 VB.Net 6.5 凸包和凸缺陷

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

sgsegse

c语言中的小小白-CSDN博客c语言中的小小白关注算法,c,c语言,贪心算法,链表,mysql,动态规划,后端,线性回归,数据结构,排序算法领域.https://blog.csdn.net/bhbcdxb123?spm1001.2014.3001.5343 给大家分享一句我很喜欢我话&#xff1a; 知不足而奋进&#xff0c;望远山而前行&am…

货车制造5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

货车制造5G智能工厂工业物联数字孪生平台&#xff0c;推进制造业数字化转型。随着5G技术的飞速发展与工业物联网的深度融合&#xff0c;货车制造5G智能工厂工业物联数字孪生平台应运而生&#xff0c;它不仅重新定义了生产模式&#xff0c;更以强大的技术驱动力&#xff0c;推动…

开放世界目标检测:检测区分出未知物体

开放世界目标检测&#xff1a;检测区分出未知物体 01 Abstract 开放世界目标检测旨在识别未见过类别的目标&#xff0c;并在提供注释后逐步识别这些目标。与传统的只限于预定义类别的范式不同&#xff0c;这种设置承诺通过使用与类别无关的信息来持续且通用地估计目标性。然而…

Java码农35岁之后只能送外卖?

声明&#xff1a;此篇为 ai123.cn 原创文章&#xff0c;转载请标明出处链接&#xff1a;https://ai123.cn/2208.html Hey&#xff0c;Java界的小伙伴们&#xff0c;有没有感受到互联网行业这一场没有硝烟的“代际战争”&#xff1f;&#x1f916;&#x1f4a5; 关于“35岁后只…

配电房挂轨机器人巡检系统的主要优点包括

背景 配电房是724h工作的封闭环境&#xff0c;人工巡检无法在时间上和空间上对配电室进行全量监控。有限的巡检时间&#xff0c;必然带来设备运转的黑盒时间&#xff0c;设备故障和隐患无法及时监控与消缺。因而不可避免存在漏检、误检的情况&#xff0c;不仅容易隐藏电力系统…

AI Agent产品经理血泪史:一年来我摸过的那些石头【Tools篇】

前几天刚好看到一篇关于GPT-6的报道&#xff0c;才想起来还有这麽回事情&#xff0c;于是赶紧把草稿捞出来改改交个任务。 至于为什麽贴这张图&#xff0c;以及为什麽血泪史从Tools开篇。 那是因为你看&#xff0c;即使到了GPT-6的时代&#xff0c;Tools仍然是AI Agent落地的…

ElementPlus下拉框输入框对齐问题

1.问题 2.解决方法 2.1label-width 说明&#xff1a;el-form中label-width设置为auto 2.2 label-wdith固定值 说明&#xff1a;如果在el-form-item里面设置了label-width"100px"&#xff1b;采用宫格布局。 .demo-one{display: grid;grid-template-columns: repe…

C++:vector篇

前言&#xff1a; 本篇仅介绍vector中常用的函数接口&#xff0c;如果需要详细的请到官网查看。 vector是一种动态数组&#xff0c;能够自动调整大小。与数组类似&#xff0c;vector使用连续内存来存储元素&#xff0c;允许高效访问&#xff0c;但可以动态增加容量。为了应对容…

买了服务器后如何正确挂载数据盘|什么是系统盘,什么是数据盘

一、前言 我们买了服务器后&#xff0c;一般会再买一个数据盘&#xff0c;如果没有数据盘&#xff0c;万一服务器系统出现问题后数据丢失就完了&#xff0c;什么数据都没了&#xff0c;所以为了避免意外的发生&#xff0c;我们通常会再买一个数据盘 如上图&#xff0c;我就在…

差一点通关某公司面试靶场

没有web4和web8&#xff0c;web2的4没做出来。 web1 国光ssrf改版靶场 1 直接读取flag 3 使用file协议读取hosts IP为172.18.240.5 dict探针内网主机开启常见端口 172.18.240.1:80 172.18.240.5:3306 172.18.240.1:3306 172.18.240.5:80 172.18.240.5:8080 172.18.240.1:…

RocketMQ Dashboard

rocketmq-dashboard是一个可视化查看和管理RocketMQ消息队列的工具 官方地址&#xff1a;RocketMQ Dashboard | RocketMQ 1、点击下载源码 2、下载并解压&#xff0c;切换至源码目录rocketmq-dashboard-1.0.0 3、修改配置文件 4、编译 rocketmq-dashboard打成jar包 &#xf…

【2024最新】注册Github账号图文教程

GitHub 是一个全球最大的开源代码托管平台&#xff0c;它提供了基于 Git 的版本控制和协作功能&#xff0c;使开发者能够共享、管理和协作开发项目。用户可以创建、克隆、编辑代码&#xff0c;并通过分支、合并请求等工具进行协同工作。GitHub 还提供社区交流、项目管理和代码审…

qt圆环饼状图,非常小的窗口都能显示

非常小的窗口都能显示 QT core gui charts#include <QtCharts> using namespace QtCharts;//创建饼状图 void MainWindow::createpieSewies() {//饼状图QPieSeries * my_pieSeries new QPieSeries();//中间圆与大圆的比例my_pieSeries->setHoleSize(0.35);//…

Spring MVC、Spring Boot和Spring Cloud

一、Spring MVC 主要特点 传统的基于Servlet的Web框架: 需要手动配置Servlet、Filter等。 配置灵活: 可以使用XML或Java类来定义Bean和依赖关系。 依赖于Web容器: 需要部署到外部Web容器&#xff08;如Tomcat、Jetty&#xff09;中运行。 视图技术支持: 支持JSP、Thymelea…

DALI-2 NFC调光解码方案,电源模块,解码板

DALI-2 DT6 NFC 调光模块 一、产品概述 深圳锐科光电科技有限公司的DALI2 DT6&D4i&#xff0c;NFC调光模块&#xff0c;符合IEC62386-101 Ed2.0、IEC62386-102 Ed2.0和 IEC62386-207 Ed1 adapted to Ed2&#xff08;DT6&#xff09;标准协议。采用国外进口单片机芯片&#…

阮一峰《TypeScript 教程》学习笔记一类型系统、数组、元祖

阮一峰《TypeScript 教程》 本篇文章主要记录浏览阮一峰《TypeScript 教程》书籍的过程中本人不会的一些TypeScript的用法。当然&#xff0c;可以说&#xff0c;我都不会哈哈哈&#xff0c;不过有的用法比较奇葩的我就不记录了&#xff0c;只记录我觉得项目中会用到&#xff0c…

Python类型检查器库之typeshed使用详解

概要 在 Python 开发中,类型检查器(如 mypy)和 IDE(如 PyCharm)能够显著提高代码的可读性和可维护性。然而,Python 本身是一种动态类型语言,标准库和第三方库通常没有类型注解。这就需要一个包含这些库类型信息的资源库,以便类型检查器能够正常工作。Typeshed 正是这样…

【Python】学习Python的流程,有这一篇资料就够了,带你深入了解Python!!!

点击免费领取《CSDN大礼包》&#xff1a;Python入门到进阶资料 & 实战源码 & 兼职接单方法 安全链接免费领取 书籍推荐 《Python编程:从入门到实践》 作者&#xff1a;埃里克马瑟斯&#xff08;Eric Matthes&#xff09;特点&#xff1a;通过实际项目引导读者学习Pyt…

前端生成验证码

一.效果图 二、实现 2.1html <template><div class"outer-box"><div class"code-box"><div class"inout-code"><label class"label" for"inputCode">验证码&#xff1a;</label><…