[算法] 优先算法(二): 双指针算法(下)

news2025/1/17 2:54:42

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(94平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
🍬算法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12676091.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
在这里插入图片描述

目录

  • 1. 有效三角形的个数(难度:🔵2度)
  • 2.两数之和(难度:🟢1度)
  • 3. 三数之和(难度:🟠4度)
  • 4.四数之和(难度:🔴5度)

1. 有效三角形的个数(难度:🔵2度)

OJ链接

  • 题目描述

购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况,返回任一结果即可。
示例 1:
输入:price = [3, 9, 12, 15], target = 18
输出:[3,15] 或者 [15,3]
示例 2:
输入:price = [8, 21, 27, 34, 52, 66], target = 61
输出:[27,34] 或者 [34,27]

  • 算法原理
    先将数组排序
    我们可以固定⼀个==「最⻓边」,然后在⽐这条边⼩的有序数组中找出⼀个⼆元组==,使这个⼆元组之和⼤于这个最⻓边。由于数组是有序的,我们可以利⽤「对撞指针」来优化。
    设最⻓边枚举到i 位置,区间[left, right] 是i 位置左边的区间(也就是⽐它⼩的区间):
    • 如果nums[left] + nums[right] > nums[i] :
      • 说明[left, right - 1] 区间上的所有元素均可以与nums[right] 构成⽐nums[i] ⼤的⼆元组
      • 满⾜条件的有right - left 种
      • 此时right 位置的元素的所有情况相当于全部考虑完毕, right– ,进⼊下⼀轮判断
    • 如果nums[left] + nums[right] <= nums[i] :
      • 说明left 位置的元素是不可能与[left + 1, right] 位置上的元素构成满⾜条件的⼆元组
      • left 位置的元素可以舍去, left++ 进⼊下轮循环
  • 代码编写
class Solution {
    public int triangleNumber(int[] nums) {
        Arrays.sort(nums);
        int ret = 0;
        for (int n = nums.length-1;n >= 2;n--){//n固定最大边
            int left = 0;
            int right = n-1;
            while (left < right){
                if (nums[left] + nums[right] <= nums[n]){//舍去比right小的元素
                    left++;
                }else{//比left大的元素全部符合条件
                    ret+=right-left;
                    right--;
                }
            }
        }
        return ret;
    }
}

2.两数之和(难度:🟢1度)

OJ链接

  • 题目描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

  • 算法原理
    • 初始化left , right 分别指向数组的左右两端(这⾥不是我们理解的指针,⽽是数组的下
      标)
    • 当left < right 的时候,⼀直循环
      • 当nums[left] + nums[right] == target 时,说明找到结果,记录结果,并且返回;
      • 当nums[left] + nums[right] < target 时:
        • 对于nums[left] ⽽⾔,此时nums[right] 相当于是nums[left] 能碰到的最⼤值别忘了,这⾥是升序数组)。如果此时不符合要求,说明在这个数组⾥⾯,没有别的数符合nums[left] 的要求了(最⼤的数都满⾜不了你,你已经没救了)。因此,我们可以⼤胆舍去这个数,让left++ ,去⽐较下⼀组数据;
        • 那对于nums[right] ⽽⾔,由于此时两数之和是⼩于⽬标值的, nums[right] 还可以选择⽐nums[left] ⼤的值继续努⼒达到⽬标值,因此right 指针我们按兵不动;
      • 当nums[left] + nums[right] > target 时,同理我们可以舍去nums[right] (最⼩的数都满⾜不了你,你也没救了)。让right– ,继续⽐较下⼀组数据,⽽left 指针不变(因为他还是可以去匹配⽐nums[right] 更⼩的数的)。
  • 代码编写
class Solution {
    public int[] twoSum(int[] price, int target) {
        int left = 0;
        int right = price.length-1;
        while (left < right){
            if (price[left]+price[right] == target){
                return new int[]{price[left],price[right]};
            }else if (price[left]+price[right] < target){
                left++;
            }else{
                right--;
            }
        }
        return new int[0];
    }
}

3. 三数之和(难度:🟠4度)

OJ链接

  • 题目描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

  • 算法原理
    与两数之和稍微不同的是,题⽬中要求找到所有「不重复」的三元组。那我们可以利⽤在两数之和那⾥⽤的双指针思想,来对我们的暴⼒枚举做优化:
    • 排序
    • 然后固定⼀个数a
    • 在这个数后⾯的区间内,使⽤「双指针算法」快速找到两个数之和等于-a 即可
      但是要注意的是,这道题⾥⾯需要有==「去重」操作==~
    • 找到⼀个结果之后, left 和right 指针要「跳过重复」的元素
    • 当使⽤完⼀次双指针算法之后,固定的a 也要「跳过重复」的元素

最后一点要注意的是在去重操作移动指针的时候,不要出现越界情况.
还有一点小优化就是,在i遍历到>0的数据的时候,就可以停止了,这是因为在剩下的数字中再也找不得两个数字加起来等于负数了.

  • 代码编写
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ret = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0;i < nums.length;){
            if (nums[i] > 0){//遇到大于0的,一定没有两个数使得条件成立
                break;
            }
            int left = i + 1;
            int right = nums.length-1;
            while(left < right){
                if (nums[left] + nums[right] == -nums[i]){
                    List<Integer> a = new ArrayList<>();
                    a.add(nums[i]);
                    a.add(nums[left]);
                    a.add(nums[right]);
                    ret.add(a);
                    left++;
                    right--;
                    while(left < nums.length && nums[left] == nums[left-1]){//left去重,且不可以越界
                        left++;
                    }
                    while(right > 0 && nums[right] == nums[right+1]){//right去重且不可以越界
                        right--;
                    }
                }else if (nums[left] + nums[right] < -nums[i]){//与前面两数之和的原理相同
                    left++;
                }else{
                    right--;
                }
            }
            //i去重
            i++;
            while(i < nums.length && nums[i] == nums[i-1]){//不可以越界
                i++;
            }
        }
        return ret;
    }
}

4.四数之和(难度:🔴5度)

  • 题目描述

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

  • 算法原理
    a. 依次固定⼀个数a
    b. 在这个数a 的后⾯区间上,利⽤
    「三数之和」找到三个数
    ,使这三个数的和等于target -a 即可。
  • 代码编写
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ret = new ArrayList<>();
        Arrays.sort(nums);
        for (int i = 0; i < nums.length;){
            for (int j = i+1;j < nums.length;){
                int left = j+1;
                int right = nums.length-1;
                long t = (long)target-nums[j]-nums[i];
                while(left < right){
                    if (nums[left] + nums[right] == t){
                        List<Integer> a = new ArrayList<>();
                        a.add(nums[left]);
                        a.add(nums[right]);
                        a.add(nums[j]);
                        a.add(nums[i]);
                        ret.add(a);
                        left++;
                        right--;
                        while(left < nums.length && nums[left] == nums[left-1]){
                            left++;
                        }
                        while(right > 0 && nums[right] == nums[right+1]){
                            right--;
                        }
                    }else if(nums[left] + nums[right] < t){
                        left++;
                    }else{
                        right--;
                    }
                }
                j++;
                while(j < nums.length && nums[j] == nums[j-1]){
                    j++;
                }
            }
            i++;
            while(i < nums.length && nums[i] == nums[i-1]){
                i++;
            }
        }
        return ret;
    }
}

从今天的代码中,我们可以发现,这几道题目在不停的利用数组的单调性和双指针在优化暴力解法,排除掉暴力解法中的一些无效情况,以后在我们做题的时候,要充分利用单调性和双指针的配合.

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

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

相关文章

Rust学习心得

我分享一下一年的Rust学习经历&#xff0c;从书到代码都一网打尽。 关于新手如何学习Rust&#xff0c;我之前在Hacker News上看到了这么一篇教程&#xff1a; 这篇教程与其他教程不同的时&#xff0c;他不是一个速成教程&#xff0c;而是通过自己的学习经历&#xff0c;向需要…

mac安装两个版本谷歌浏览器;在mac运行不同版本的chrome浏览器

场景 正常情况下&#xff0c;mac上只能安装一个版本的chrome浏览器&#xff0c;即使你安装了两个版本的&#xff0c;打开老旧版本时候也会自动切换成最新版的浏览器 故本文主要解决如何下载和在mac运行不同版本的chrome浏览器 文章目录 场景一、下载1.mac本身就有一个最新版ch…

【MySQL】库的操作和表的操作

库的操作和表的操作 一、库的操作1、创建数据库(create)2、字符集和校验规则&#xff08;1&#xff09;查看系统默认字符集以及校验规则&#xff08;2&#xff09;查看数据库支持的字符集&#xff08;3&#xff09;查看数据库支持的字符集校验规则&#xff08;4&#xff09;校验…

网关路由SpringCloudGateway、nacos配置管理(热更新、动态路由)

文章目录 前言一、网关路由二、SpringCloudGateway1. 路由过滤2. 网关登录校验2.1 鉴权2.2 网关过滤器2.3 登录校验2.3.1 JWT2.3.2 登录校验过滤器 3. 微服务从网关获取用户4. 微服务之间用户信息传递 三、nacos配置管理问题引入3.1 配置共享3.1.1 在Nacos中添加共享配置3.1.2 …

Kubectl 的使用——k8s陈述式资源管理

一、kebuctl简介: kubectl 是官方的CLI命令行工具&#xff0c;用于与 apiserver 进行通信&#xff0c;将用户在命令行输入的命令&#xff0c;组织并转化为 apiserver 能识别的信息&#xff0c;进而实现管理 k8s 各种资源的一种有效途径。 对资源的增、删、查操作比较方便&…

MobaXterm下载虚拟机SSH链接超时解决(保姆级踩坑)

文章目录 为啥要用MobaXtermMobaXterm下载打开虚拟机ssh链接ssh连接失败排查linux配置windows配置 到这了&#xff0c;什么都干了&#xff0c;怎么还不成功&#xff1f; 更多相关内容可查看 在一个阳光明媚的下午&#xff0c;开启了无限踩坑的旅程 为啥要用MobaXterm 作为小编…

高性能负载均衡的分类及架构分析

如何选择与部署适合的高性能负载均衡方案&#xff1f; 当单服务器性能无法满足需求&#xff0c;高性能集群便成为提升系统处理能力的关键。其核心在于通过增加服务器数量&#xff0c;强化整体计算能力。而集群设计的挑战在于任务分配&#xff0c;因为无论在哪台服务器上执行&am…

解决脚本刷服务器导致卡顿宕机的问题

在互联网服务领域&#xff0c;自动化脚本的不当使用或恶意攻击可能会导致服务器资源被过度消耗&#xff0c;从而引发服务响应缓慢甚至系统崩溃。特别是在电商、游戏、社交平台等领域&#xff0c;这种现象尤为常见。本文将深入探讨脚本刷服的常见形式、其对服务器性能的影响&…

面向对象-----继承

前面向大家介绍了面向对象中的封装性&#xff0c;今天再来向大家介绍面向对象的继承和多态的两大特性。 1.继承 1.1 为什么需要继承&#xff1f; 在java语言中&#xff0c;我们用类来描述世间万物&#xff0c;虽然万物非常复杂&#xff0c;但总有一些共同点&#xff0c;如果…

Java NIO 基础

Java NIO 基础 1. NIO 介绍2. NIO 三大组件2.1 Channel2.1.1 常见的 Channel2.1.2 常用方法 2.2 Buffer2.2.1 常见的 Buffer2.2.2 重要属性2.2.3 常用方法 2.3 Selector2.3.1 四种事件类型 1. NIO 介绍 NIO&#xff08;non-blocking io&#xff09;&#xff1a;非阻塞IO&#…

2024.5.20 学习记录

1、react 原理&#xff08;jsx的本质、事件机制原理、setState和batch Update、组件渲染更新和diff算法、fiber&#xff09; 2、代码随想录贪心刷题

【C++初阶】--- C++入门(上)

目录 一、C的背景及简要介绍1.1 什么是C1.2 C发展史1.3 C的重要性 二、C关键字三、命名空间2.1 命名空间定义2.2 命名空间使用 四、C输入 & 输出 一、C的背景及简要介绍 1.1 什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&…

GPT-4o 引领人机交互新风向的向量数据库Milvus Cloud 成本

成本 AIGC 时代对于冷热储存的呼唤 成本一直是向量数据库获得更广泛使用的最大阻碍之一,这个成本来自两点: 储存,绝大多数向量数据库为了保证低延迟,需要把数据全量缓存到内存或者本地磁盘。在这个动辄百亿量级的AI 时代,意味着几十上百 TB 的资源消耗。 计算,数据需…

OCR版面分析-- PaddleOCR(python 文档解析提取)

1. 创建新的conda环境 # 在命令行输入以下命令&#xff0c;创建名为paddle_env的环境 # 此处为加速下载&#xff0c;使用清华源 conda create --name paddle_env python3.8 --channel https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ # 这是一行命令2. 激活刚创建…

全球视频会议软件巨头Zoom,率先引入后量子端到端加密

5月21日&#xff0c;Zoom Video Communications公司宣布&#xff0c;后量子端到端加密&#xff08;E2EE&#xff09;现已面向全球推出&#xff0c;适用于Zoom Workplace。目前&#xff0c;Zoom已将该功能加入Zoom Meetings&#xff0c;稍后将扩展至Zoom Phone和Zoom Rooms。 图…

数据中心大型AI模型网络需求

数据中心大型AI模型网络需求 随着Transformer的崛起和2023年ChatGPT的大规模应用&#xff0c;业界逐渐形成共识&#xff1a;遵循一定的规模效应原则&#xff0c;增加模型参数量能够显著提升模型性能。特别是在参数数量级跃升至数百亿乃至更高时&#xff0c;大型AI模型在语言理…

20232803 2023-2024-2 《网络攻防实践》实践十报告

目录 1. 实践内容1.1 SEED SQL注入攻击与防御实验1.2 SEED XSS跨站脚本攻击实验(Elgg) 2. 实践过程2.1 SEED SQL注入攻击与防御实验2.1.1 熟悉SQL语句2.1.2 对SELECT语句的SQL注入攻击2.1.3 对UPDATE语句的SQL注入攻击2.1.4 SQL对抗 2.2 SEED XSS跨站脚本攻击实验(Elgg)2.2.1 发…

超前预热|博睿数据将应邀出席双态IT用户大会,分享《构建云原生时代的一体化智能可观测性》

5月31日&#xff0c;第十二届双态IT用户大会将于成都盛大开幕&#xff0c;此次大会由DCMG和双态IT论坛联合主办&#xff0c;聚焦“信创时代的组织级云原生能力建设”和“组织级云原生运维能力建设”两大会议主题&#xff0c;旨在推动双态IT落地与创新&#xff0c;为企业数字化转…

Android AV World 序

序 做Android系统开发很久了&#xff0c;基于高通和MTK硬件平台&#xff0c;使用Android10量产了一些车载项目。由于功能模块属于系统底层支撑&#xff0c;类似于docker&#xff0c;涉及到音视频的处理&#xff0c;及Display Graphics的一些处理&#xff0c;需要调试解决显示花…

【map、set】C++用红黑树来封装map、set容器

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; C进阶 &#x1f389;其它专栏&#xff1a; C初阶 | Linux | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解map和set之用红黑树来封装map、set容器的相关内容。 如果看到最后您…