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

[Lc双指针_2] 盛水最多的容器 | 有效三角形的个数 | 和为S的两个数字

目录

🎢1. 盛水最多的容器

题解

代码

🎢2. 有效三角形的个数

题解

代码

3. 和为S的两个数字

解法


前文回顾:[Lc优选算法] 快慢指针 | 移动零 | 复写零 | 快乐数

🎢1. 盛水最多的容器

题目链接:11.盛水最多的容器

题目描述

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0)(i, height[i])

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

示例 1:

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

木桶 效应:

  • 两个长度 ,选择最低的才是 木桶盛水高度

8*5=40

7*7=49

示例 2:

输入:height = [1,1]
输出:1

提示:

  • n == height.length
  • 2 <= n <= 105
  • 0 <= height[i] <= 104

题解

解法一:暴力求解(O(N^2)会超时)

枚举出能构成的所有容器,找出其中容积最大的值。

容器容积的计算方式:

  • 设两指针 i , j ,分别指向水槽板的最左端以及最右端,此时容器的 宽度为 j - i 。由于容器的⾼度由两板中的短板决定,因此可得 容积公式 : v = (j - i) * min( height[i], height[j] )
class Solution {
public:
    int maxArea(vector<int>& height) {
        int n=height.size(),ret=0,v=0;

//n-1 是要运行的
        for(int i=0;i<n;i++)
        {
            for(int j=1;j<n;j++)
            {
                v=(j-i)*min(height[i],height[j]);
                ret=max(v,ret);
            }
        }
        return ret;
    }
};

常见报错 可参考这篇文章:

解法二:暴力优化 双指针(对撞指针)

为了⽅便叙述,假设「左边边界」⼩于「右边边界」

  • 发生移动,容器的宽度⼀定变⼩
  • 由于左边界较⼩,决定了⽔的⾼度
    • 如果改变左边界,新的⽔⾯⾼度不确定,因此容器的容积 可能 会增⼤
  • 但是对于移动 右边界 的情况

【设置 固定场景,发现这种规律之后,我们就可以来实现优化啦】

  • 由此可⻅,左边界和其余边界的组合情况都可以舍去
    • 所以可以left++跳过这个边界,继续去判断下⼀个左右边界

移动 h 较小的部分,它才有机会变大

我们设计的边界情况,就可以利用 单调性

使从边界向内移,w 一定会减小

  • 不断重复上述过程,每次都可以舍去⼤量不必要的枚举过程,直到leftright相遇
    • 期间产⽣的所有的容积⾥⾯的最⼤值,就是最终答案

代码

设计场景:从边界向内移,w 一定会减小,重点:是去移动 值最小的指针,看它有没有机会变大~

class Solution {
public:
    int maxArea(vector<int>& height) {
        int ret=0,v=0;
        int left=0,right=height.size()-1;

 //不相遇 就一直判断       
        while(left!=right)
        {
            int h=min(height[left],height[right]);
            v=(right-left)*h;
            ret=max(ret,v);
            if(height[left]>height[right]) right--;
            else left++;
        }
        return ret;
    }
};

🎢2. 有效三角形的个数

题目链接:633.有效三角形的个数

题目描述

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

示例 2:

输入: nums = [4,2,3,4]
输出: 4

题解

一般三角形我们判断方法是任意两边之和大于第三边

算法原理:

解法一: 暴力求解

  • 选三个数进行判断,一般我们一定会想到 三层for循环进行判断,下面是伪代码,时间复杂度O(N^3)
for(int i;i<n-2;i++)
    for(int j=i+1;j<n-1;j++)
        for(int k=j+1;k<n;k++)
            check(i,j,k);

关于 for 循环判断的理解:

for(int i;i<n;i++)

//-->

while(!(i<n))
{
    int i;
    //run
    i++;
}
//++到 直到 小于一个数就不要了

解法二:利用单调性,使用双指针算法来解决问题

任意两边之和大于第三边,三个数需要判断三次

a+b>c

a+c>b

b+c>a

现在a、b、c三个数,先对它们进行排序,a<=b<=c;

a+b>c

a+c>b

b+c>a

我们只需要判断一次 a+b>c就也把下面两次判断包括了。因为c是最大的!

所以排序实现了对要检查三次的优化

但是我们的循环还是要,嵌套三次,怎么办呢?

通过 移动双指针,我们可以 优化 1 层循环能快速找到 所有成立情况

if (nums[left] + nums[right] > nums[max])

  • 说明[left, right - 1]区间上的所有元素均可以与nums[right]构成⽐nums[max]⼤的⼆元组
  • 共有 right - left 
  • 因为,移动左指针,就都是成立的,此时 right位置的元素的所有情况相当于全部考虑完毕,right--,减小第二个元素,进⼊下⼀轮判断

if (nums[left] + nums[right] <= nums[max])

  • 说明left位置的元素是不可能与[left + 1, right]位置上的元素构成满⾜条件的⼆元组
  • left位置的元素可以舍去
  • left++,提升第三个元素,进⼊下一判断

注意这只是固定了10 的一次循环,还要在从后往前固定

  1. 固定 最大的数
  2. 在最大数的左区间内,使用双指针算法,快速统计符合要求的三元组个数

代码

class Solution {
public:
    int triangleNumber(vector<int>& nums) 
    {
//利用 迭代器排序
        sort(nums.begin(),nums.end());

        int ret=0;
        int n=nums.size();
    
        for(int k=n-1;k>=2;k--)   
        {
            
//left和right是每次k都要变化的
            int left=0,right=k-1;

            while(left<right)
          {
            if(nums[left]+nums[right]>nums[k])
            {
                ret+=(right-left);
                //中间 剩下的这些,就都是成立的了


                right--;//判断下一个 第二个元素
            }

           else
            {
                //直到找到 可以搭配第二个元素的 第三个元素
                left++;
            }
          }
        }
        return ret;
    }
};

3. 和为S的两个数字

题目链接:JZ57 和为S的两个数字

题目描述

输入一个升序数组 array 和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,返回任意一组即可,如果无法找出这样的数字,返回一个空数组即可。

数据范围: 0≤len(array)≤105 0≤len(array)≤105 , 1≤array[i]≤106 1≤array[i]≤106

示例1

输入:[1,2,4,7,11,15],15复制
返回值:[4,11]复制
说明:返回[4,11]或者[11,4]都是可以的   

示例2

输入:[1,5,11],10复制
返回值:[]复制
说明:不存在,返回空数组     

解法

解法一:暴力枚举求解O(N^2)
拿到题我们马上就会想到暴力求解,两层for循环,以下是伪代码
 

解法2:使用单调性,使用双指针算法解决问题
本题排好序了,我们直接使用双指针即可,一个指向最左边,一个指向最右边。然后根据条件利用单调性一次排除一批。O(N)


http://www.kler.cn/a/566951.html

相关文章:

  • Spring Boot 消息队列(以RabbitMQ为例)
  • Java注释/JDK开发工具生成API/关键字、标识符规范
  • 企业级本地知识库部署指南(Windows优化版)
  • 什么是 Prompt?——一篇详细的介绍
  • FloodFill 算法(典型算法思想)—— OJ例题算法解析思路
  • Win 11 C盘相邻的分区是恢复分区导致无法扩容
  • PDF文件转换为PNG图像
  • DH法建立6自由度机械臂正运动学模型
  • 数据库设计报告
  • 介绍一款飞算JavaAI编程工具,集成到idea,图文并茂
  • Graph Convolutional Networks(GCN)图卷积网络
  • 解释 Node.js 中的异步编程模型,如何使用回调、Promise 和async / await 处理异步操作?
  • PyCharm Python 环境配置指南
  • HTTP3.0 和 HTTP2.0,HTTP1.0区别
  • 前端存储方案全面对比:localStorage、sessionStorage、cookies与IndexedDB
  • 【 开发知识点 一 】 随机数生成器 /dev/urandom 和 /dev/random
  • 第一届启航杯-web-misc(全)
  • 如何查看react的版本号
  • 如何长期保存数据(不包括云存储)最安全有效?
  • 决策树:机器学习中的分类与回归利器