目录

6.力扣 11.盛水最多的容器

6.1 题目解析:

6.2 算法思路:

6.2.1 暴力解法:

6.2.2 优化算法:

6.3 代码演示:

​编辑

6.4 总结反思:

7.力扣 611.有效的三角形个数

7.1 题目解析:

 7.2 算法思路:

7.3 代码演示:

​编辑

 7.4 总结反思:

8.力扣 LCR.179 查找总价格为目标值的两个商品

8.1 题目解析:

8.2 算法思路:

8.2.1 暴力解法:

8.2.2 优化解法:

​编辑8.3 代码演示:

​编辑

 8.4 总结反思:

9.力扣 15.三数之和

9.1题目解析:

9.2 算法思路:

9.3 代码演示 :

9.3.1 正确代码演示:

9.3.2 错误代码演示:

9.4 总结反思:

10.力扣 18.四数之和

10.1 题目解析:

10.2 算法思路:

 10.3 代码演示:

10.4 反思总结:


6.力扣 11.盛水最多的容器

6.1 题目解析:

其实这道题目呢,就是让你在给定的数组内寻找到两个数相乘的最大值(但这i两个数字不是随便的两个数,由题意可得,这个“高”其实是遵循的是短板效应,即看的是短的那一边。)

6.2 算法思路:

6.2.1 暴力解法:

其实,当咱们看到一道题目的时候,最先想到的应该就是暴力解法,这道题也有对应的暴力解法。就是一个一个的进行枚举,相乘,然后选出最大的值即可。当然,容器的容积的计算:

1.首先得从height[i],height[j]中选出最小的值。

2.之后计算j-i的值,之后相乘即可。

那么咱们来看一下暴力解法的伪代码:

for(int i=0;i<n;i++)for(int j=i+1;j<n;j++)check(nums[i],nums[i])

但是这样写的话,一旦给的数组里面的元素特别多,就会超时,所以第一种方法不可取。

6.2.2 优化算法:

这种算法是根据暴力解法的枚举改进而来。暴力解法为什么会超时?是因为它进行了太多的无意义的比较。 

就拿这个进行举例子,暴力是不管三七二十一,直接全部进行相乘,然后比较。咱们其实可以带一带脑子,比如上图,你让j往左挪动,这个j-i是一直在减小的。而且,j往左挪动,由于挪动的边始终比i小,所以高也是在不段减小的。所以这个时候,就不需要再进行比较了,因为从i到j之间,不可能有比(j-i)*j更大的。那么此时就不需要比较这一部分。

还有一点就是,咱们要移动就移动短边,为什么呢?因为你越往内,这个长度越小,那么想找到比原来面积大的,只能靠高(找到比原来更高的高)。而咱们知道,这个受限于短板,所以高的大小得看短板,并且动短边,高度变大的可能性更大。想一想,因为它是取决于短边的。

所以,动的时候,先去比较左右板谁小,谁小谁就动,动完后再进行面积的计算,再比较这个面积与原面积,留下面积比较大的那一个。

6.3 代码演示:

int main()
{vector<int> height = { 1,8,6,2,5,4,8,3,7 };int ret = 0;int left = 0;int right = height.size() - 1;while (left < right){int tmp = min(height[left], height[right]) * (right - left);ret = max(ret, tmp);//找出最大的之间也要进行比较,选出更大的if (height[right] > height[left]){left++;}else{right--;}}cout << ret << endl;return 0;
}

 代码就是左右板,谁小就动谁。

6.4 总结反思:

对于很多的题来说,优化的算法都是在暴力的基础上进行改良的。所以咱们一开始想不到优化的解法,不用慌张,先写出来暴力解法,然后再仔细的分析。

7.力扣 611.有效的三角形个数

7.1 题目解析:

这道题的题意很好理解,就是给你一个数组,返回数组里面可以组成三角形的三元组的个数即可。

 7.2 算法思路:

相信大家都知道判断三角形的条件是任意两边之和大于第三边。但是呢,这个其实需要三个条件。但是呢,还有一种方法,只需要一个条件便可以判断出是否为三角形。

前提是咱们得知道这三条边的大小。

好,那么接下来讲解一下这道题运用到的算法思路:

找单调,然后用双指针解决这道问题:

1.首先得先排好序,因为要用那个结论,就得保证是升序的。

2.那么利用有序数组就是使用单调性。怎么个单调法呢?

3.首先固定住一个最大的数字。

4.在最大的数字的左边的区间内,使用双指针法计算出符合要求的三元组的个数。

很明显,得有两层循环才能完成吧。

 

假设此时a+b>c,那么从a往右一直到b这个区间内,都是比a大的,那么这个区间内的再加上b是不是也是一定大于c的?好,那么这个时候,你要是挪动a就没有任何意义了。这个时候,只需要往左挪动b即可。

 

此时的a+b<c,好,那么此时,从b往左一直到a的位置,这个区间内的值都是小于b的,所以a加上这个区间内的任意一个值,肯定也都是小于c的。所以此时挪动b无意义,需要将a往左挪动。

............以此类型。直到left>=right为止。

这才是完成了一个小循环,之后在移动c,再进行下一个小循环。

所以 

那么到现在为止,代码相信大家都可以自己写出来了吧。

7.3 代码演示:

int main()
{vector<int> nums = { 2,2,3,4 };//1.先进行排序sort(nums.begin(), nums.end());//2.进行计算个数int ret = 0;int n = nums.size();for (int i = n - 1; i >= 2; i--){int left = 0;int right = i - 1;while (left < right){if (nums[left] + nums[right] > nums[i]){ret += right - left;right--;}else{left++;}}}cout << ret << endl;return 0;
}

这是一个三元数组,所以c得到下标为2的位置停下。以及left与right必须得写在for里面,因为left,right随着c的变化为发生位置变化。 

 7.4 总结反思:

其实这道题也就是带我们认识到了单调性+双指针对于这类型题目的解法,为下面三道题打下了基础。

8.力扣 LCR.179 查找总价格为目标值的两个商品

8.1 题目解析:

题目很简单,就是给定一个数组,再给定一个值,让你在数组中寻找两个元素和为目标值的二元数组,并且不管元素顺序,返回一种叫即可。

8.2 算法思路:

8.2.1 暴力解法:

这道题搭眼一看,就知道肯定有暴力解法,就是写两层for循环,然后再将元素想加,看看哪两个元素相加等于目标值,再返回这两个元素组成的二元数组。但是这种解法容易超时,所以咱们重点来讲解第二种优化算法。

8.2.2 优化解法:

其实这个题的解法与上一题的解法基本一致,咱们来看图理解:

8.3 代码演示:

vector<int> Judgment(vector<int>& price, int target)
{int left = 0;int right = price.size() - 1;while (left < right){if (price[left] + price[right] > target){right--;}else if (price[left] + price[right] < target){left++;}else return { price[left],price[right] };//多参数隐式类型转换}return{ -1,-1 };//确保每个路径下都有返回值
}

 8.4 总结反思:

这道题与上一道题的解法基本一致。

9.力扣 15.三数之和

9.1题目解析:

题目也挺好理解的,就是i,j,k三个元素相加为0,并且这三个元素不可以是同一个位置的,并且返回的时候,三元数组中的元素相同的,只能返回一组,这个意味着咱们是不是要进行去重呀。那去重的话,咱们肯定可以想到C++里面的unordered_set,使用容器去重。当然可以,但是,有没有不使用容器就可以进行去重的呢?有!方法,咱们算法思路里面讲解。

9.2 算法思路:

其实 ,这道题,你只要做过前面的那个题,这个题的算法思路就很容易想到。

好,这个题基本的核心的思路我已经全部罗列出来了,大家可以看一下。但这个地方,本博主写代码的时候,还是被弄晕了。

9.3 代码演示 :

9.3.1 正确代码演示:

vector<vector<int>> threeSum(vector<int>& nums)
{sort(nums.begin(), nums.end());vector<vector<int>> ret;int n = nums.size();int i = 0;while (i < n){int left = i + 1; int right = n - 1;while (left < right){if (nums[left] + nums[right] == -nums[i]){vector<int> frontret = { nums[left],nums[right],nums[i] };ret.push_back(frontret);left++, right--;// 去重操作left和right,先++left,--right,再去重//先去重,再移动left与right的方法不可取while (left < right && nums[left] == nums[left - 1]) left++;while (left < right && nums[right] == nums[right + 1])right--;}else if (nums[left] + nums[right] > -nums[i]){right--;}else {left++;}}i++;//外层i去重while (i < n && nums[i] == nums[i - 1]) i++;}return ret;
}
int main()
{vector<int> nums = { 2,-3,0,-2,-5,-5,-4,1,2,-2,2,0,2,-4,5,5,-10 };vector<vector<int>> kk = threeSum(nums);for (auto& e : kk){for (auto& m : e){cout << m << "";}cout << endl;}cout << endl;
}

这个地方的去重操作呢,必须得是先进行left,right的移动,之后再判断这个位置与前一个位置的数字是否相等,如果相等,再加加,挪到要改变的那个元素的位置上。这是正确的逻辑。但是博主呢,正好逻辑相反,结果就这一个题在那里调试了一下午。

9.3.2 错误代码演示:

去重逻辑混乱,不可取
vector<vector<int>> threeSum(vector<int>& nums)
{sort(nums.begin(), nums.end());vector<vector<int>> ret;int n = nums.size();int i = 0;while (i < n){int cout_i = 0;int left = i + 1; int right = n - 1;while (left < right){int cout_left = 0;int cout_right = 0;if (nums[left] + nums[right] == -nums[i]){vector<int> frontret = { nums[left],nums[right],nums[i] };ret.push_back(frontret);while ((left + 1 < n - 1) && (nums[left] == nums[left + 1])){if (left < n - 1){left += 1;cout_left++;}}while ((right - 1 > i + 1) && (nums[right] == nums[right - 1])){if (right > i + 1){right -= 1;cout_right++;}}if ((left < n - 2) && (cout_left == 0)){left++;}if ((right > i + 2) && (cout_right == 0)){right--;}}else if (nums[left] + nums[right] > -nums[i]){right--;}else {left++;}}while ((i + 1 < n - 2) && (nums[i] == nums[i + 1])  ){if (i < n - 2){i += 2;cout_i++;}}if (cout_i == 0){i++;}}return ret;
}
int main()
{vector<int> nums = { 2,-3,0,-2,-5,-5,-4,1,2,-2,2,0,2,-4,5,5,-10 };vector<vector<int>> kk = threeSum(nums);for (auto& e : kk){for (auto& m : e){cout << m << "";}cout << endl;}cout << endl;
}

这是我写的代码,我的本意是想着既然都去重了,那就先去重,如果重复了,那就加到不重复为止,且这种最后不需要再单独加加了。之后再单独加。但是呢,不对 。

1. **去重指针移动不正确**:在找到一组解后,对`left`和`right`的去重没有正确地将指针移动到下一个不同元素的位置。例如,如果`left`位置有重复,它只是移动到了重复序列的最后一个,然后停止,这样下一次循环还是相同的值(因为下一次循环时,`left`指向的还是重复序列的最后一个,而下一个元素就是不同的,但此时`left`并没有指向下一个不同元素,所以循环会继续使用这个重复序列的最后一个元素,导致重复解)。

2. **去重后指针移动逻辑混乱**:通过`cout_left`和`cout_right`来决定是否再移动一次,这种逻辑没有道理。而且,在去重循环中,它只移动了重复元素,但并没有确保移动后的指针指向的是一个新的值(即跳过重复后应该指向下一个不同的值)。

3. **固定数`i`的去重逻辑错误**:使用`i+=2`来跳过重复,这会导致当重复次数为奇数时,最后一个重复值仍然会被处理,造成重复解。而且,当重复次数超过2次时,跳跃步长固定为2,显然不够。

只能说,我还是个新手吧哈哈哈哈,做题做的还是少。

9.4 总结反思:

这道题想要真正的自己用代码实现出来,真的挺不容易的。还是要多练习题目。

10.力扣 18.四数之和

10.1 题目解析:

你仔细的读一读这道题,会发现,这道题的解法与前面那个三数之和的解法基本一致。无非就是外面多套了层循环,多加了一个去重。

10.2 算法思路:

若还是不能够理解,那么我画一张图就可以了:

1.依次固定一个数a

2.在a后面的区间内,利用“三数之和”找到三个数,使这三个数的和等于target-a即可

        2.1 依次固定一个数b

        2.2 在b后面的区间内,利用“双指针”找到两个数,使得两个数的和为target-a-b即可

最后别忘了去重细节,有三个,left与right,b,a

以及还有越界的情况。最后考虑清楚,会发现与三数之和的代码差不多一样的。 

 10.3 代码演示:

//四数之和思想与三数之和基本一致,连去重方法都是一样的
vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ret;sort(nums.begin(), nums.end());int n = nums.size();for (int i = 0; i < n;) {for (int j = i + 1; j < n;) {int left = j + 1;int right = n - 1;long long aim = (long long)target - nums[i] - nums[j];while (left < right) {if (nums[left] + nums[right] ==aim) {vector<int> frontret = { nums[left], nums[right],nums[i], nums[j] };ret.push_back(frontret);++left;--right;// 只有这样写才能确保最后一个位置的元素是在不重复的那个位置底下while (left < right && nums[left] == nums[left - 1]) {left++;}while (left < right && nums[right] == nums[right + 1]) {right--;}}else if (nums[left] + nums[right] >aim) {right--;}else {left++;}}j++;while (j < n && nums[j] == nums[j - 1]) {j++;}}i++;while (i < n && nums[i] == nums[i - 1]) {i++;}}return ret;
}

 三个去重以及边界判定别忘了。

10.4 反思总结:

题目之间都是相互连接的,咱们只有真正弄懂了一道题目,理解其中的解法,再遇到下一个题目的时候,才有应对之策,才能临阵不慌。

...............本篇完

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为OD 消消乐游戏

1. 题意 游戏规则&#xff1a;输入一个只包含英文字母的字符串&#xff0c;字符串中的两个字母如果相邻且相同&#xff0c;就可以消除。 在字符串上反复执行消除的动作&#xff0c;直到无法继续消除为止&#xff0c;此时游戏结束。 输出最终得到的字符串长度。 输入 输入原始…

小白学HTML,操作HTML文件篇(2)

目录 一、添加多媒体 1.添加网页图片 2.添加网页音频 3.添加网页视频 二、创建容器 1. 标签 2.布局 三、创建表格 1.表格标签 2.添加表格表头 3.添加表格标题 一、添加多媒体 在 HTML 网页中可以轻松地使用标签来添加图片、音频、视频等多媒体&#xff0c;而这些多媒体并…

微服务架构中实现跨服务的字段级权限统一控制

结合集中式权限管理、分布式上下文传递、动态策略执行等技术 ​​一、核心架构设计​​ ​​1. 分层控制模型​​ ​​网关层​​:统一校验用户身份与基础权限,拦截非法请求。 ​​服务层​​:基于用户权限动态过滤数据字段,实现业务级控制。 ​​策略中心​​:集中管理权…

【实现100个unity特效之27】使用unity的ShaderGraph实现一个带裁剪边缘光的裁剪效果(2d3d通用)

文章目录普通裁剪效果1、创建一个Lit Shader Graph2、ShaderGraph前置配置3、添加节点4、效果5、修改裁剪方向带边缘色的裁剪1、在裁剪的基础上添加裁剪边缘光2、边缘的亮度3、修改裁剪方向4、效果5、我们可以代码控制它的变化&#xff0c;如下2D3D游戏通用专栏推荐完结普通裁剪…

Android Scoped Storage适配完全指南

Android Scoped Storage适配完全指南关键词&#xff1a;Android、Scoped Storage、适配、存储权限、文件访问摘要&#xff1a;本文将全面介绍Android Scoped Storage的相关知识&#xff0c;从背景出发&#xff0c;详细解释核心概念&#xff0c;阐述其原理和架构&#xff0c;给出…

Typecho集成PHPMailer实现邮件订阅功能完整指南

文章目录 Typecho使用PHPMailer实现文章推送订阅功能详解 1. 背景与需求分析 1.1 为什么选择PHPMailer 1.2 功能需求 2. 环境准备与配置 2.1 安装PHPMailer 2.2 数据库设计 3. 核心功能实现 3.1 邮件服务封装类 3.2 订阅功能实现 3.2.1 订阅表单处理 3.2.2 确认订阅处理 3.3 文…

无线-二层组网-直接转发

文章目录无线二层组网直接转发&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;Datacom专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2025年07月16日08点00分 无线二层组网 直接转发 本地转发中所有的沿途都需要配置对应VLAN的通过&#xff…

gin go-kratos go-zero框架对比

Gin、Go-Kratos 和 Go-Zero 是 Go 语言中三种常见的服务框架&#xff0c;它们在定位、设计理念、复杂度和适用场景上差异较大。下面我们从功能定位、设计理念、优劣对比、使用建议等维度进行深入对比。&#x1f9ed; 一句话总结框架定位Gin轻量级、高性能的 HTTP 路由框架Go-Kr…

4G模块 A7670发送英文短信到手机

命令说明ATi显示产品的标志信息 ATCIMI查询IMSI ATCICCID从SIM卡读取ICCID ATCGSN查询产品序列号 ATCPIN查询卡状态 ATCSQ查询信号强度 ATCGATT查询当前PS域状态 ATCREG查询GPRS注册状态 ATCEREG查询4G注册状态 ATCGPADDR查询PDP地址 ATCMGF选择短信格式 ATCMGS发送短信流程第一…

归并排序递归法和非递归法的简单简单介绍

基本思想&#xff1a; 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个…

webrtc之子带分割下——SplittingFilter源码分析

文章目录前言一、频带分割过程1.SplittingFilter的创建2.频带分割整体流程1&#xff09;分割时机2&#xff09;分割规则3&#xff09;分割核心代码3.频带合并二、算法实现1.实现原理介绍2.All pass QMF系统源码1&#xff09;提高精度2&#xff09;经过串联全通滤波器3&#xff…

Java运维之Tomcat升级

Tomcat升级准备工作 下述所有过程中,包含了两种升级方式,一种是备份旧版本的 bin 和 lib,将新版本的 bin 和 lib 对旧版本进行覆盖;另一种是直接备份旧版本的Tomcat包,运行新版本,将旧版本的配置文件(conf/ * )和应用(webapps/ * )等同步到新版本。 1. 到官网下载指…

MySQL的可重复读隔离级别实现原理分析

MySQL 的 可重复读&#xff08;Repeatable Read, RR&#xff09; 隔离级别主要通过 多版本并发控制&#xff08;Multi-Version Concurrency Control, MVCC&#xff09; 和 锁机制&#xff08;特别是间隙锁&#xff09; 来实现的。其核心目标是&#xff1a;在一个事务内&#xf…

利用Java自定义格式,循环导出数据、图片到excel

利用Java自定义格式&#xff0c;循环导出数据、图片到excel1、自定义格式循环导出数据1.1.设置格式1.1.1、居中样式1.1.2、应用样式到合并区域1.1.3、合并单元格1.1.4、设置列宽1.2、写入数据1.2.1、创建标签头部1.2.2、写入标签内容2、自定义格式循环导出图片2.1、设置格式并插…

SAP学习笔记 - 开发45 - RAP开发 Managed App New Service Definition,Metadata Extension

上一章讲了在 Data Model View ( CDS View for BO Structure )基础上创建 Projection View ( CDS View for BO Projection )。 SAP学习笔记 - 开发44 - RAP开发 Managed App 建 Projection View&#xff0c;Provider Contract&#xff0c;用 redirected to 设定父子关系-CSDN博…

React强大且灵活hooks库——ahooks入门实践之高级类hook(advanced)详解

什么是 ahooks&#xff1f; ahooks 是一个 React Hooks 库&#xff0c;提供了大量实用的自定义 hooks&#xff0c;帮助开发者更高效地构建 React 应用。其中高级类 hooks 是 ahooks 的一个重要分类&#xff0c;专门用于处理一些高级场景&#xff0c;如受控值、事件发射器、性能…

计算机网络——数据链路层(25王道最新版)

数据链路层前言数据链路层的功能封装成帧&#xff08;组帧&#xff09;字符计数法字节填充法零比特填充法违规编码法小节差错控制检错编码奇偶校验码CRC校验码&#xff08;循环冗余校验码&#xff09;基本思想如何构造如何检错纠错纠错编码海明校验码设计思路求解步骤&#xff…

【PTA数据结构 | C语言版】字符串替换算法

本专栏持续输出数据结构题目集&#xff0c;欢迎订阅。 文章目录题目代码题目 请编写程序&#xff0c;将给定主串 s 中的子串 sub_s 替换成另一个给定字符串 t&#xff0c;再输出替换后的主串 s。 输入格式&#xff1a; 输入给出 3 个非空字符串&#xff0c;依次为&#xff1a…

事物生效,订单类内部更新订单

代码如下以下代码1不生效&#xff0c;2生效解决方案1&#xff0c;外层方法加注解&#xff0c;内层不加2&#xff0c;不要拆分方法&#xff0c;把更新订单操作放在带事物的大方法中3&#xff0c;拆方法&#xff08;内部&#xff09;&#xff0c;注入自己&#xff0c;用代理对象调…

非对称加密:RSA

文章目录 非对称加密:RSA 1、RSA 加解密 2、RSA 生成密钥对(公钥、私钥)、加解密 参考资料 非对称加密:RSA 1、RSA 加解密 <!-- RSA --><!-- 引入jsencrypt库 --><script src="https://cdn.bootcdn.net/ajax/libs/jsencrypt/3.3.2/jsencrypt.min.js&q…