【八】【算法分析与设计】双指针(2)

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。

示例 2:

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

提示:

  • n == height.length

  • 2 <= n <= 10(5)

  • 0 <= height[i] <= 10(4)

暴力求解:

 
class Solution {
public:int maxArea(vector<int>& height) {int n=height.size();int max=INT_MIN;for(int i=0;i<n;i++){for(int j=i+1;j<n;j++){max=fmax(max,(j-i)*min(height[i],height[j]));}}return max;}
};

双指针优化暴力解法:

我们首先研究一小段区间[left,right]内最大的盛水体积。

先计算leftright的最大盛水体积,记为ret。如果height[left]<=height[right],那么对于left与任意其他下标组合,计算出来的体积都一定小于ret。因为left与其他任意下标组合(记为right1),right1-left一定小于rifht-left。而计算体积的高度是取决于高度小的那一个,高度h=min(height[right1],height[left])。体积v=(right1-left)*h。高度h=height[left],或者h<height[left]。所以体积v一定小于ret。也就是left与其他位置下标的组合都可以不用计算。

 
class Solution {
public:int maxArea(vector<int>& height) {int left = 0, right = height.size() - 1, ret = 0;while (left < right) {int v = (right - left) * fmin(height[left], height[right]);ret = max(ret, v);if (height[left] <= height[right]) {left++;} elseright--;}return ret;}
};

函数接收一个整数类型的向量 height,向量的每个元素代表一个竖直线的高度,这些竖直线的宽度假设为1,函数返回由这些线形成的容器可以容纳的最大水量。

int left = 0, right = height.size() - 1, ret = 0;

初始化三个整数变量:left 设置为0,表示向量的起始索引;right 设置为 height.size() - 1,即向量的最末索引;ret 初始化为0,用于存储最大的水容量。

while (left < right) {

使用一个循环来遍历所有可能的容器。当 left 索引小于 right 索引时,循环继续。

int v = (right - left) * fmin(height[left], height[right]);

计算当前 leftright 索引之间形成的容器可以容纳的水量。水量由两个竖直线之间的距离(right - left)和两条线中较短一条的高度(fmin(height[left], height[right]))的乘积得出。

ret = max(ret, v);

更新 ret,使其始终保持为迄今为止找到的最大水容量。

if (height[left] <= height[right]) { left++; } else right--;

根据 leftright 索引处的高度比较结果,移动 leftright 索引。如果 left 处的高度小于等于 right 处的高度,则 left 索引向右移动(left++);否则,right 索引向左移动(right--)。这是基于贪心算法的思想,即保留较高的竖直线以期望找到更大的水容量。

时间复杂度和空间复杂度分析

时间复杂度:O(n),其中 n 是向量 height 的长度。这是因为我们只需要一次遍历就可以找到最大的水容量,left 从向量的起始位置向右移动,right 从向量的末尾位置向左移动,直到它们相遇。

空间复杂度:O(1),因为我们只使用了常数级别的额外空间,即几个变量来存储索引和计算结果。

611. 有效三角形的个数

给定一个包含非负整数的数组 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

提示:

  • 1 <= nums.length <= 1000

  • 0 <= nums[i] <= 1000

暴力枚举:

判断a,b,c三个数是否可以组成三角形,只需要满足a+b>c,a+c>b,b+c>a三个条件即可。如果a,b,c三个数满足a<=b<=c有序的条件,我们只需要判断a+b>c满足即可组成三角形。原因是a+c>bb+c>a是一定成立的,因为c已经大于等于ab了,再加上一个正数不等式一定成立。

所以我们的思路是先把nums数组排序,排序后再暴力枚举三个数。满足条件就ret++

 
class Solution {
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(), nums.end());int n = nums.size();int ret = 0;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;}
};

双指针优化暴力枚举:

先对nums数组排序。

研究[a,c]区间所有可以组成三角形的情况。首先固定最大的数c。记left=0,right=c-1

对于left,right,c三个数的组合,如果nums[left]+nums[right]>c说明可以组成三角形。对于left+1,right,c三个数,一定也可以组成三角形。因为left+1>left,而函数是递增的。所以nums[left+1]>nums[left],nums[left+1]+nums[left]>c。以此类推,对于与right的组合,一共有right-left个数可以组成三角形。考虑完与right的组合所有情况,就right--,不考虑right的组合情况了。

如果nums[left]+nums[right]<=c,说明不可以组成三角形。对于left,right-1,c三个数,一定也不可以组成三角形。因为right-1<right,而函数是递增的。所以nums[right-1]<nums[right],nums[right-1]+nums[left]<c。以此类推,对于与left的组合,都不可以组成三角形。考虑完与left的组合所有情况,就left++,不考虑left的组合情况了。

 
class Solution {
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(), nums.end());int ret = 0, 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]) {ret += right - left;right--;} else {left++;}}}return ret;}
};

首先对数组 nums 进行排序,这样我们可以利用三角形两边之和大于第三边的性质来简化问题。

int ret = 0, n = nums.size();

声明并初始化变量 ret 为0,它将用来计数可以构成三角形的三元组数量。变量 n 存储数组 nums 的大小。

for (int i = n - 1; i >= 2; i--) {

从数组的最后一个元素开始向前遍历,直到第三个元素(索引为2)。这是因为我们至少需要三个数来构成一个三角形。这个遍历的是最大的边长的所有可能。

int left = 0, right = i - 1;

在每次循环中,初始化两个指针 leftright,分别指向当前考察的三元组中最小元素的索引和次大元素的索引。

while (left < right) {

left 指针小于 right 指针时,执行循环体内的操作。这个循环用于找出在固定最大边 nums[i] 的情况下,有多少对 (nums[left], nums[right]) 能与 nums[i] 构成三角形。

if (nums[left] + nums[right] > nums[i]) { ret += right - left; right--; } else { left++; }

如果 nums[left]nums[right] 之和大于 nums[i],则说明找到了一组有效的三元组,因为数组已经排序,所以从 leftright 之间的所有数都可以与 nums[right]nums[i] 构成三角形。因此,将 right - left 的值累加到 ret 中,然后将 right 指针向左移动一位,以考察下一对可能的三元组。否则,如果两数之和不大于 nums[i],与left的所有组合都无法组成三角形,则将 left 指针向右移动一位,增大两数之和的值。

时间复杂度和空间复杂度分析

时间复杂度:O(n^2),其中 n 是数组 nums 的长度。这是因为我们首先对数组进行了排序,这需要 O(n log n) 的时间。之后,我们有一个外层循环(O(n))和一个内层循环(O(n)),外层和内层循环的组合将会产生 O(n^2) 的时间复杂度。

空间复杂度:O(log n),这是排序所需要的空间复杂度。除了排序之外,我们只使用了几个变量来存储索引和计算结果。

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

购物车内的商品价格按照升序记录于数组 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]

提示:

  • 1 <= price.length <= 10^5

  • 1 <= price[i] <= 10^6

  • 1 <= target <= 2*10^6

暴力枚举:

 
class Solution {
public:vector<int> twoSum(vector<int>& price, int target) {int n = price.size();for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {if (price[i] + price[j] == target)return {price[i], price[j]};}}return {-1, -1};}
};

双指针优化暴力枚举:

只考虑[left,right]区间内的数据。

如果price[left]+price[right]>target,那么对于right与其他位置的数据的组合,一定也大于target,因为函数是递增的。因此对于right与其他位置的数据不需要再考虑。right--。

如果price[left]+price[right]<target,那么对于left与其他位置的数据的组合,一定也小于target,因为函数是递增的。因此对于left与其他位置的数据不需要再考虑,left++。

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

int left = 0, right = price.size() - 1;

初始化两个指针 leftright,分别指向数组 price 的开始和结束位置。

while (left < right) {

使用一个循环来查找两个数。当 left 指针小于 right 指针时,循环继续。

int sum = price[left] + price[right];

计算 leftright 指针指向的两个数的和。

if (sum > target) { right--;

如果计算出的和大于 target,则将 right 指针向左移动,以减小和的值。对于right与其他任何位置的组合,sum一定也大于target,所以不需要再考虑与right有关的组合。

} else if (sum < target) { left++;

如果计算出的和小于 target,则将 left 指针向右移动,以增大和的值。对于left与其他任何位置的组合,sum一定也小于target,所以不需要再考虑与left有关的组合。

} else return {price[left], price[right]};

如果计算出的和等于 target,则返回一个包含这两个数的数组。

return {-1, -1};

如果在循环结束时没有找到符合条件的两个数,则返回 {-1, -1}。这个操作是为了迎合编译器,因为题目意思显然是一定存在两个数之和为target。因此在while语句中一定会返回,但是如果不在外面写return,编译器会认为这个代码可能存在无返回值。因此在外面也写return是为了迎合编译器。

时间复杂度和空间复杂度分析

时间复杂度:O(n),其中 n 是数组 price 的长度。这是因为我们使用了双指针方法遍历数组,每个元素最多被访问一次。

空间复杂度:O(1),因为我们只使用了常数级别的额外空间,即几个变量来存储索引和计算结果,不需要额外的空间来存储数据。

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

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

相关文章

react可视化编辑器 第三章 限制移动范围

代码 import React, {useState,DragEvent,useRef,useEffect,MouseEvent, } from react; // import { throttle } from lodash;interface Demo {id: number;x: number;y: number; }const App: React.FC () > {const [demos, setDemos] useState<Demo[]>([]);// let …

JMeter 面试题及答案整理,最新面试题

JMeter中如何进行性能测试的规划和设计&#xff1f; 进行JMeter性能测试的规划和设计主要遵循以下几个步骤&#xff1a; 1、确定测试目标&#xff1a; 明确性能测试的目的和目标&#xff0c;比如确定要测试的系统性能指标&#xff08;如响应时间、吞吐量、并发用户数等&#…

Linux第80步_使用“信号量”实现“互斥访问”共享资源

1、创建MySemaphoreLED目录 输入“cd /home/zgq/linux/Linux_Drivers/回车” 切换到“/home/zgq/linux/Linux_Drivers/”目录 输入“mkdir MySemaphoreLED回车”&#xff0c;创建“MySemaphoreLED”目录 输入“ls回车”查看“/home/zgq/linux/Linux_Drivers/”目录下的文件…

嵌入式硬件设计(一)|利用 NodeMCU-ESP8266 开发板和继电器结合APP“点灯•blinker”制作Wi-Fi智能开关(附有关硬件详细资料)

概述 本文主要讲述利用 NodeMCU-ESP8266 开发板和继电器通过手机 APP “ 点灯 • Blinker ” 制作一款能够由手机控制的WiFi 智能开关&#xff0c;从而实现智能物联。NodeMCU 是基于 Lua 的开源固件&#xff0c;ESP8266-NodeMCU是一个开源硬件开发板&#xff0c;支持WiFi功能&a…

redis瘦身版

高可用&#xff1a; 主从 哨兵&#xff1a;sentinel&#xff1a; 集群监控 消息通知 故障转移 配置中心 redis cluster &#xff1a;livu livechat中使用了 人家有槽slot 16384个呢 请求发送任意节点 该节点会将请求发送到正确节点上-相亲相爱 1.哈希的方式&#xff0c;将数据…

数字万用表 (Digital Multimeter)

数字万用表 [Digital Multimeter] 1. Product parameters2. 交流频率测量3. 面板介绍4. 背光屏References 1. Product parameters 2. 交流频率测量 在交流 750V 档处按 HOLD 键切换到市电频率 3. 面板介绍 4. 背光屏 ​ References [1] Yongqiang Cheng, https://yongqiang…

Leet code 91 解码方法

解题思路&#xff1a;动态规划 创建一个数组dp记录到达每个位置时候次数 解码时候要么在该位置单独解码 要么就是和前一个位置共同解码 第一步考虑 下标0位置能否单独解码 如果可以单独解码dp[0] 在0位置有一种解码方式 假如在下标1位置 dp[1]的结果是多少呢 然后再考虑…

Swift 面试题及答案整理,最新面试题

Swift 中如何实现单例模式&#xff1f; 在Swift中&#xff0c;单例模式的实现通常采用静态属性和私有初始化方法来确保一个类仅有一个实例。具体做法是&#xff1a;定义一个静态属性来存储这个单例实例&#xff0c;然后将类的初始化方法设为私有&#xff0c;以阻止外部通过构造…

maven工程,未被idea识别为maven工程怎么办?

示例&#xff1a;以下工程的pom文件图标不是一个蓝色的m&#xff0c;所以未被识别为maven工程。 解决办法&#xff1a;打开pom.xml文件—>右键—>add as maven project 问题解决&#xff1a;

第二门课:改善深层神经网络<超参数调试、正则化及优化>-超参数调试、Batch正则化和程序框架

文章目录 1 调试处理2 为超参数选择合适的范围3 超参数调试的实践4 归一化网络的激活函数5 将Batch Norm拟合进神经网络6 Batch Norm为什么会奏效&#xff1f;7 测试时的Batch Norm8 SoftMax回归9 训练一个SoftMax分类器10 深度学习框架11 TensorFlow 1 调试处理 需要调试的参…

Lua中文语言编程源码-第一节,更改llex.c词法分析器模块, 使Lua支持中文关键词。

源码已经更新在CSDN的码库里&#xff1a; git clone https://gitcode.com/funsion/CLua.git 在src文件夹下的llex.c&#xff0c;是Lua的词法分析器模块。 增加中文保留字标识符列表&#xff0c;保留英文保留字标识符列表。 搜索“ORDER RESERVED”&#xff0c;将原始代码 …

CSS学习(2)-盒子模型

1. CSS 长度单位 px &#xff1a;像素。em &#xff1a;相对元素 font-size 的倍数。rem &#xff1a;相对根字体大小&#xff0c;html标签就是根。% &#xff1a;相对父元素计算。 注意&#xff1a; CSS 中设置长度&#xff0c;必须加单位&#xff0c;否则样式无效&#xff…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Row)

沿水平方向布局容器。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 可以包含子组件。 接口 Row(value?:{space?: number | string }) 从API version 9开始&#xff0c;该接口支持在…

HTML5CSS3提高导读

HTML5CSS3提高导读 2024/2/20 HTML5 的新增特性主要是针对于以前的不足&#xff0c;增加了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题&#xff0c;基本是 IE9 以上版本的浏览器才支持&#xff0c;如果不考虑兼容性问题&#xff0c;可以大量使用这 …

基于opencv的图像处理系统的设计与实现

概要 随着计算机技术的飞速发展&#xff0c;图像技术在各领域的研究和应用日渐深入和广泛。opencv是近年来推出的开源、免费的计算机视觉库,利用其所包含的函数可以很方便地实现数字图像处理。本文旨在对opencv进行一个快速全面简介,通过介绍图像处理的相关函数&#xff0c;使读…

如何重置iPhone的网络设置?这里提供详细步骤

前言 本文介绍如何重置iPhone上的网络设置。该信息适用于iPhone 12到iPhone 6以及iOS 14到iOS 8。 如何在iPhone上重置网络设置 采取以下步骤重置iPhone上的网络设置&#xff1a; 1、在iPhone上&#xff0c;打开设置应用程序。 2、单击通用。 3、滚动到屏幕底部&#xff…

知名Web3投资基金a16z合伙人Jane Lippencott确认出席Hack.Summit() 2024区块链开发者大会

在区块链技术的风起云涌和Web3生态的蓬勃发展中&#xff0c;知名a16z Crypto的合伙人Jane Lippencott已确认出席即将于2024年4月9日至10日在香港数码港举行的Hack.Summit() 2024区块链开发者大会。作为亚洲首次举办的Hack.Summit()&#xff0c;此次大会将为全球区块链开发者及业…

智慧城市与数字孪生:共创未来城市的智慧生活

目录 一、智慧城市与数字孪生的概念与特点 二、智慧城市与数字孪生共创智慧生活的路径 1、城市规划与建设的智能化 2、城市管理与服务的智慧化 3、城市安全与应急管理的智能化 三、智慧城市与数字孪生面临的挑战与对策 四、智慧城市与数字孪生的发展趋势与展望 1、技术…

HttpServer整合模块设计与实现(http模块五)

目录 类功能 类定义 类实现 编译测试 源码路标 类功能 类定义 // HttpServer模块功能设计 class HttpServer { private:using Handler std::function<void(const HttpRequest &, HttpResponse &)>;std::unordered_map<std::string, Handler> _get_r…