当前位置: 首页 > news >正文

双指针算法篇——一快一慢须臾之间解决问题的飘逸与灵动(2)

 

前言:

上篇我们讲解了双指针算法的含义以及相关题型讲解,本次则趁热打铁,通过进阶题目的分析与讲解,促使我们更深入和灵活的理解运用双指针算法。

 相关题目及讲解

一. 盛最多水的容器

题目链接:11. 盛最多水的容器 - 力扣(LeetCode)

题目分析:

1. 该题要求找到一个区间,数组内存储的元素即代表其对应的高度,宽度则为首尾元素下标之差

2. 根据木桶效应,两个板子一高一低,所能容纳水的高度应该为高度较低的那个

3. 因此,我们只需要逐个遍历相乘,求最大值即可

思路讲解:

1. 暴力解法(会超时)

直接逐个遍历所有结果,并逐次比较,选取最大的区间即可。

设两指针 i , j ,分别指向⽔槽板的最左端以及最右端,此时容器的宽度为 j - i 。由于
容器的⾼度由两板中的短板决定,因此可得容积公式 : v = (j - i) * min( height[i], height[j])

代码示例如下: 

class Solution {
public:int maxArea(vector<int>& height) {int n = height.size();int ret = 0;// 两层 for 枚举出所有可能出现的情况for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {// 计算容积,找出最⼤的那⼀个ret = max(ret, min(height[i], height[j]) * (j - i));}}return ret;}
};

 2. 对撞指针

由上述分析可知,装水容器的容积由高度和宽度确定。

我们不妨令左边界为left,右边界为right,假设left[height]<right[height],那么高度就会取左边界的高度,宽度即为right-left。

现在假设固定一个区间进行遍历,分以下几种情况讨论:

1)固定右边界,左边界向右遍历,宽度一定减小,高度的变化不确定,但一定不会大于右区间的高度,因此容积可能增大,也可能减小。

2)固定左区间,右区间向左遍历,宽度一定减小,高度只会变小或不变,因此容积一定减小

由此可见,固定高度较小区间的情况下容积大小的变化是确定的,因此我们只需固定高度较大的区间遍历即可,这样即可省去大量重复的计算比较。

代码实现:

class Solution {
public:int maxArea(vector<int>& height) {int ret=0;//最大容积int left=0,right=height.size()-1;//确定左右区间while(left<right){int v=min(height[left],height[right])*(right-left);ret=max(ret,v);//求最大容积if(height[left]<height[right]){left++;}else{right--;}}return ret;}
};

 二. 有效三角形的个数

题目链接:611. 有效三角形的个数 - 力扣(LeetCode)

题目分析:

1. 题目要求找出数组内可以组成三角形的种类个数,需注意,元素的大小可以重复,但是不能是数组内的同一个元素重复组合。

2. 判定方法:两小数之和大于大数,大数减次小数之差大于最小数

思路讲解:

判定方法中谈到了数大小的比较,因此我们可以先选择对数组进行排序

解法一:暴力解放(会超时)

排序后直接3个for循环进行遍历,此时时间复杂度已经来到了恐怖的n的三次方,基本上都会超时。

代码示例如下:  

class Solution {
public:int triangleNumber(vector<int>& nums) {// 1. 排序sort(nums.begin(), nums.end());int n = nums.size(), ret = 0;// 2. 从⼩到⼤枚举所有的三元组for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {for (int k = j + 1; k < n; k++) {// 当最⼩的两个边之和⼤于第三边的时候,统计答案if (nums[i] + nums[j] > nums[k])ret++;} }}return ret;}
};

解法二:双指针算法

在排序之后,我们可以首先固定一个最长边,假设其位置位于i处,则其坐区间[left,right]内的元素全部小于i处的元素,同时分以下几种情况讨论:

注意:此时区间内left处元素最小,right处元素最大!!!

1. nums[left]+nums[right]>nums[i],说明满足条件,且该区间内所有元素与right组合均可满足条件,此时right--,缩小区间继续判断

2. nums[left]+nums[right]<=nums[i],说明此时和较小,需要left++,寻找更大的元素进行判断

代码实现:

class Solution {
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(),nums.end());//排序int sum=0;//种类个数总和int n=nums.size();//总元素个数for(int i=n-1;i>=2;i--){int left=0,right=i-1;while(left<right){if(nums[left]+nums[right]>nums[i]){sum+=right-left;right--;}//区间内均满足,右区间向左遍历if(nums[left]+nums[right]<=nums[i]){left++;}//小于,左区间向右遍历}}return sum;}
};

小结:

本篇内容就到此为止啦!欢迎各位佬前来支持斧正,祝大家生活愉快,万事胜意!!!

 


http://www.mrgr.cn/news/66522.html

相关文章:

  • 【OJ题解】C++实现反转字符串中的每个单词
  • Zabbix低权限SQL注入至RCE+权限绕过
  • 四款主流的3D创作和游戏开发软件的核心特点和关系
  • 【UGUI】实现点击注册按钮跳转游戏场景
  • 解读JobScheduler的jobs.xml
  • yaml文件编写
  • triangle_area_calculators库发布
  • 进程信号——信号的保存
  • 聚划算!Transformer-LSTM、Transformer、CNN-LSTM、LSTM、CNN五模型多变量回归预测
  • 0.推荐序
  • 3.5 windows xp ReactOS EiAllocatePool()
  • [代码随想录打卡Day7] 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和
  • GCC编译器的`-Wall`、`-Wextra`和`-pedantic`选项解读
  • Vue3-子传父
  • ORA-00020和ORA-00603报错处理
  • 【算法】递归+深搜:106.从中序与后序遍历序列构造二叉树(medium)
  • B2118 验证子串
  • Swift 开发教程系列 - 第5章:集合类型
  • oracle数据检查方法
  • 多client向同一个pushgateway推送指标被覆盖问题
  • 解密抖音推荐算法:个性化内容背后的技术奥秘
  • 【MongoDB】MongoDB的聚合(Aggregate、Map Reduce)与管道(Pipline) 及索引详解(附详细案例)
  • 一篇文章速通Java开发Stream流(流水线开发附斗地主小游戏综合案例)
  • 一文快速预览经典深度学习模型(一)——CNN、RNN、LSTM、Transformer、ViT
  • Vue:计算属性
  • JavaScript 变量作用域与函数调用机制:var 示例详解