初识算法 · 双指针(3)

初识算法 · 双指针(3)

目录

前言:

和为s的两数之和

题目解析:

​编辑

算法原理:

算法编写:

三数之和

题目解析

算法原理

算法编写


前言:

本文通过介绍和为S的两数之和,以及三数之和,对双指针算法进行深一步的了解,介绍该算法博主使用三部曲,第一步对题目进行分析,里面会夹杂着暴力解法的问题,第二步对于算法原理进行分析,第三步则是对算法进行编写,最后分析时间复杂度,可能会分析空间复杂度。

题目的链接为:

LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode)

15. 三数之和 - 力扣(LeetCode)

那么话不多说,进入正题吧!


和为s的两数之和

题目解析:

该题目的要求是找到两个数,这两个数相加的和是等于target的。题中也有个很重要的条件,按照升序记录于数组中,这个升序是十分关键的。我们直接探讨暴力解法,即将所有的两数之和举例出来,第一次相等就返回即可,如果运气差点,就需要遍历完整个数组两次,即两个for循环,此时的时间复杂度为O(N^2),这是暴力解法,是比较容易想出来的:

for (int i = 0; i < price.size();i++) { for (int j = 0;j < price.size();j++) { //判断是否满足条件 } }

当然了,如果使用暴力解法,那么我们对题目的升序就没有任何使用了,就很吃亏,所以现在进入算法原理。

算法原理:

使用双指针算法,对于题目中的升序,一定要利用好,我们知道:

target = num1 + num2

那么既然是升序的,如果我们让两个指针,一个从开始走,一个从末尾走,也就是最大的和最小的走,判断结果,大于了target,右指针往左边走,反之亦然,这时候其实已经做完题目了。

对于循环来说,只有一个循环,如果没有找到,返回的是个空就可以。

算法编写:

class Solution { public: vector<int> twoSum(vector<int>& price, int target) { int right = price.size() - 1, left = 0; while(left < right) { if(price[left] + price[right] == target) return {price[left],price[right]}; else if(price[left] + price[right] < target) left++; else if(price[left] + price[right] > target) right--; } return { }; } };

结束条件自然是左小于右,因为返回的是vector,都没有找到的话返回空即可,时间复杂度是O(N),没有新开空间,所以空间复杂度为O(1)。


三数之和

题目解析

由题目可得,找三个数,其中这三个数相加等于0,我们不妨将题目理解为,找一个数,该数 = 另外两数之和,是不是就感觉容易多了?不过是上文和为s的变种而已,我们只是需要将S变化一下即可。

以上是题目的最基本的要求,那么还有一个要求是,不允许出现重复的,这是和本文第一道题不同的要求,这点代表了我们要去重即可。

那么同样的,我们思考如何暴力解法?

暴力解法无非是将所有的三元组列出来,判断和是否为零,满足条件,我们可以将它丢进set,用set本身的性质进行去重即可。

但是暴力解法的时间复杂度可就高了,三个数都要单独列出,也就是需要三个循环,时间复杂度为O(N^3),往往是通过不了的。

所以,我们进入到算法原理方面。


算法原理

我们同样的使用双指针算法,因为是双指针不是三指针,所以需要我们固定一个数,用来充当target,有了第一个题目的经验,我们不妨排序一下,保证数组有序的同时有利于我们控制指针变量,排序之后对于我们去重的操作也会容易很多。

排序之后,固定好target,然后进入到第二个循环,通过双指针算法,找两个数,使该三个数相加等于0即可。

那么指针移动分为两种情况,如果前面两个数相加>target,代表right大了,需要right--,反之亦然,这是移动的情况。满足条件的话,添加进去就可以了。

那么最重要的点来了,我们如何进行去重操作呢?

判断的是nums[left] == nums[left + 1]是否相等即可,如果相等了,left就++,right同理,但是去重的不只有这两个数,还有一个数也需要去重,就是nums[i],如果i不去重,肯定是很导致很多重复的元素,毕竟都是会从头开始找的。

去重i的时候,需要控制i的移动,因为去重操作本身就会控制指针移动。


算法编写

class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> ans; sort(nums.begin(),nums.end()); for(int i = nums.size() - 1;i > 1 && nums[i] >= 0;) { int target = nums[i]; int left = 0,right = i - 1; while(left < right) { if(nums[left] + nums[right] > (-target)) right--; else if(nums[left] + nums[right] < (-target)) left++; else { ans.push_back({nums[left++],nums[right--],nums[i]}); while(left < right && nums[left] == nums[left - 1]) left++; while(left < right && nums[right] == nums[right + 1]) right--; } } i--; while(i < nums.size() && nums[i] == nums[i + 1]) i--; } return ans; } };

三个去重,一个排序,三个判断,最后返回即可。


感谢阅读!

Read more

Spring Boot 3.x开发中CSP(内容安全策略)配置导致前端资源加载失败问题详解及解决方案

目录 * Spring Boot 3.x开发中CSP(内容安全策略)配置导致前端资源加载失败问题详解及解决方案 * 引言 * 1. 问题表现:CSP拦截的典型症状 * 2. 原因分析:CSP指令与Spring Boot配置 * 2.1 CSP指令概览 * 2.2 Spring Boot 3.x 中配置CSP的方式 * 2.3 常见的配置失误 * 3. 解决方案:从诊断到修复的完整步骤 * 3.1 步骤一:查看浏览器控制台错误 * 3.2 步骤二:整理资源来源清单 * 3.3 步骤三:调整CSP策略 * 3.3.1 允许外部域名 * 3.3.2

By Ne0inhk

OpenClaw Webhook 详解:完整指南

Webhook 是将 OpenClaw 从“聊天助手”快速转变为“响应式系统”的最佳方式。无需等待您主动发送消息,GitHub 可以在 PR 提交时通知 OpenClaw,Stripe 可以在支付失败时通知 OpenClaw,n8n 也可以按计划通知 OpenClaw。OpenClaw 会接收这些传入事件,并将其转换为代理运行或轻量级唤醒操作,然后将结果路由回您实际使用的任何渠道。 本文重点介绍 OpenClaw 网关上的 HTTP Webhook。OpenClaw 中还有另一种东西,在一些文档和配置中也被称为“钩子”。这些是网关内部的事件钩子,当本地生命周期事件触发时运行。它们也很有用,但 Stripe 或 GitHub 与服务器通信的方式并非通过它们。 如果您的 OpenClaw 实例是刚刚部署在 VPS 上,并且您仍然使用 SSH 进行基本操作,那么首先要确保网关稳定,

By Ne0inhk

Web 创建设计

下面为你整理一份系统全面、通俗易懂、适合初学者与进阶者的 《Web 创建与设计指南》(Web Creation & Design Guide)。 它覆盖从网站构思、设计、前端、后端、交互、发布到维护的完整流程。 如果你愿意,我还可以将它扩展成 PDF、PPT、Markdown 或课程体系。 🌐 Web 创建与设计指南 (Web Creation & Design Guide) 1. 什么是 Web 创建与设计? Web 创建(Web Development)= 网站功能的开发(HTML/CSS/JS + 后端 + 数据库) Web 设计(Web Design)= 网站视觉与体验设计(UI/UX)

By Ne0inhk
前端与 Spring Boot 后端无感 Token 刷新 - 从原理到全栈实践

前端与 Spring Boot 后端无感 Token 刷新 - 从原理到全栈实践

🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志 🎐 个人CSND主页——Micro麦可乐的博客 🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战 🌺《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战 🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解 🌛《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用 🍎 《前端技术》专栏以实战为主介绍日常开发中前端应用的一些功能以及技巧,均附有完整的代码示例 ✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧 💕《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程 🌞《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整 👍《Spring Security》专栏中我们将逐步深入Spring Security的各个

By Ne0inhk