有n棍棍子,棍子i的长度为ai,想要从中选出3根棍子组成周长尽可能长的三角形。请输出最大的周长,若无法组成三角形则输出0。

题目描述:
有n棍棍子,棍子i的长度为ai,想要从中选出3根棍子组成周长尽可能长的三角形。请输出最大的周长,若无法组成三角形则输出0。 算法为O(nlogn)

初始理解题目

首先,我们需要清楚地理解题目要求:

  1. 输入:有n根棍子,每根棍子的长度为a_i(i从1到n)。
  2. 目标:从中选出3根棍子,组成一个三角形,且这个三角形的周长尽可能大。
  3. 输出
    • 如果可以组成三角形,输出最大的周长。
    • 如果无法组成三角形,输出0。
  4. 算法要求:时间复杂度为O(n log n)。

三角形的基本条件

要组成一个三角形,必须满足三角形不等式:对于任意三条边a, b, c(假设a ≤ b ≤ c),必须满足:

a + b > c

这是因为三角形的两边之和必须大于第三边。如果a + b ≤ c,那么这三条边无法构成一个三角形(它们要么无法闭合,要么是一条直线)。

解决思路

为了找到周长最大的三角形,我们需要考虑以下几点:

  1. 排序:首先将所有的棍子长度按非递减顺序排序。这样我们可以方便地检查连续的三个棍子是否满足三角形条件。

    • 排序的时间复杂度为O(n log n),满足题目要求。
  2. 选择最大的可能周长:为了找到周长最大的三角形,我们应该从最长的棍子开始检查。因为周长是三条边之和,更大的边更有可能带来更大的周长。

  3. 检查连续的三个棍子:从排序后的数组末尾开始,依次检查三个连续的棍子是否满足三角形不等式。具体来说:

    • 假设排序后的数组为a[0], a[1], …, a[n-1],其中a[0] ≤ a[1] ≤ … ≤ a[n-1]。
    • 从i = n-1开始,检查a[i-2], a[i-1], a[i]:
      • 如果a[i-2] + a[i-1] > a[i],那么这三根棍子可以组成三角形,且由于是从最大的开始检查,这时的周长a[i-2] + a[i-1] + a[i]就是最大的可能周长。
      • 如果不满足,则继续检查i-1, i-2, i-3的组合。
  4. 无法组成三角形的情况:如果检查完所有可能的三元组(即i从n-1降到2)都没有满足条件的,则返回0。

为什么这种方法有效?

  • 排序后检查连续的三个:因为我们需要最大的周长,所以优先检查最长的三条边。如果最长的三条不满足,那么我们需要尝试次长的三条(即去掉最长的,检查剩下的最长的三条)。
  • 贪心选择:这种从大到小检查的方法是一种贪心策略,可以确保我们尽早找到最大的可能周长,而不需要检查所有可能的三元组。
  • 时间复杂度
    • 排序:O(n log n)。
    • 检查:最多检查n-2次(从n-1到2),每次检查是O(1),所以是O(n)。
    • 总时间复杂度:O(n log n) + O(n) = O(n log n),满足要求。

示例

假设棍子长度为:[3, 4, 5, 6, 10]

  1. 排序后:[3, 4, 5, 6, 10]
  2. 检查最后三个:5, 6, 10
    • 5 + 6 > 10? 11 > 10 → 满足,周长为5 + 6 + 10 = 21
    • 因为这是第一次检查且满足,所以21就是最大的周长。

另一个例子:[1, 2, 3, 4]

  1. 排序后:[1, 2, 3, 4]
  2. 检查最后三个:2, 3, 4
    • 2 + 3 > 4? 5 > 4 → 满足,周长为2 + 3 + 4 = 9
    • 所以最大周长为9。

再一个无法组成的例子:[1, 2, 3, 5]

  1. 排序后:[1, 2, 3, 5]
  2. 检查最后三个:2, 3, 5
    • 2 + 3 > 5? 5 > 5 → 不满足(严格大于)
  3. 检查下一个:1, 2, 3
    • 1 + 2 > 3? 3 > 3 → 不满足
  4. 无法组成三角形,返回0。

伪代码

function maxTrianglePerimeter(arr):n = length(arr)if n < 3:return 0sort(arr)  // 非递减排序for i from n-1 down to 2:a = arr[i-2]b = arr[i-1]c = arr[i]if a + b > c:return a + b + creturn 0

边界情况

  1. 棍子数量少于3:无法组成三角形,直接返回0。
  2. 所有棍子长度相同
    • 例如 [4, 4, 4]:
      • 4 + 4 > 4 → 8 > 4,满足,周长为12。
  3. 多个可组成的三元组
    • 例如 [3, 4, 5, 6, 7]:
      • 检查5, 6, 7:5 + 6 > 7 → 11 > 7,周长为18。
      • 虽然3, 4, 5也满足,但周长较小,不会被选中。

为什么不能随机选择三个棍子?

因为我们需要最大的周长,所以必须从最长的棍子开始考虑。如果随机选择,可能会错过更大的周长组合,或者需要检查所有可能的三元组,导致时间复杂度增加(O(n^3))。

为什么检查连续的三个?

在排序后的数组中,连续的三个棍子(a[i-2], a[i-1], a[i])是当前最大的三个未被排除的棍子。如果a[i-2] + a[i-1] ≤ a[i],那么a[i]对于任何更小的a[j](j < i-2)也无法满足a[j] + a[k] > a[i](因为a[j] ≤ a[i-2], a[k] ≤ a[i-1]),所以可以安全地排除a[i],继续检查a[i-1]。

时间复杂度验证

  • 排序:O(n log n)。
  • 检查:单次循环,最多n-2次,每次O(1),所以O(n)。
  • 总时间:O(n log n) + O(n) = O(n log n)。

实现代码(Python示例)

def max_triangle_perimeter(arr):arr.sort()n = len(arr)for i in range(n - 1, 1, -1):a, b, c = arr[i - 2], arr[i - 1], arr[i]if a + b > c:return a + b + creturn 0# 示例
print(max_triangle_perimeter([3, 4, 5, 6, 10]))  # 输出:21 (5,6,10)
print(max_triangle_perimeter([1, 2, 3, 4]))       # 输出:9 (2,3,4)
print(max_triangle_perimeter([1, 2, 3, 5]))       # 输出:0
print(max_triangle_perimeter([4, 4, 4]))          # 输出:12 (4,4,4)
print(max_triangle_perimeter([1, 1]))             # 输出:0

可能的误区

  1. 忽略排序:如果不排序,无法有效地从大到小检查,可能导致无法找到最大周长或时间复杂度过高。
  2. 错误的不等式检查:可能会误以为只需要检查a + b > c,而忽略了a ≤ b ≤ c的假设。排序确保了这一点。
  3. 过早终止:如果在找到一个满足条件的三元组后继续寻找更大的周长,可能会浪费时间,但实际上第一次找到的已经是最大的。
  4. 处理边界条件:如棍子数量少于3时,应直接返回0。

数学证明

为了更严谨地证明这种方法的正确性:

  • 假设排序后的数组为a_1 ≤ a_2 ≤ … ≤ a_n。
  • 我们需要找到i, j, k(i < j < k)使得a_i + a_j > a_k,且a_i + a_j + a_k最大。
  • 由于数组已排序,最大的a_k是a_n。为了最大化周长,我们希望a_i + a_j尽可能大,因此选择a_{n-2}和a_{n-1}。
    • 如果a_{n-2} + a_{n-1} > a_n,则这是最大的可能周长。
    • 否则,a_n不能作为最长边,尝试a_{n-1}作为最长边,检查a_{n-3} + a_{n-2} > a_{n-1},依此类推。
  • 这种策略确保了我们在最早的可能位置找到最大的周长。

其他方法的比较

  1. 暴力法:检查所有可能的三元组,时间复杂度O(n^3),不满足要求。
  2. 固定最长边,双指针找其他两边:类似于排序后从最长边开始,用双指针寻找其他两边,但不如上述方法简洁。
  3. 动态规划:不适用于此问题,因为没有明显的子问题重叠。

优化空间

  • 如果数组中有很多重复元素,可以考虑去重,但最坏情况下不影响时间复杂度。
  • 实际实现中,排序是主要开销,可以使用内置的高效排序算法(如Timsort)。

总结

通过将棍子长度排序并从大到小检查连续的三元组,我们可以在O(n log n)的时间内找到可以组成最大周长三角形的三条边,或者确定无法组成三角形。这种方法高效且正确,满足了题目的所有要求。

C++ 实现思路

为了实现这个算法,我们需要按照以下步骤进行:

  1. 输入处理:读取输入的棍子数量 n 和棍子长度数组 a
  2. 排序:将数组 a 按非递减顺序排序。
  3. 查找最大周长三角形
    • 从数组的末尾开始,依次检查三个连续的棍子是否能组成三角形。
    • 如果能组成三角形,则返回这三个棍子的长度之和(即周长)。
    • 如果遍历完所有可能的三元组都无法组成三角形,则返回 0
  4. 输出结果:根据查找结果输出最大周长或 0

C++ 代码实现

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;long long maxTrianglePerimeter(vector<int>& a) {int n = a.size();if (n < 3) {return 0;}sort(a.begin(), a.end());for (int i = n - 1; i >= 2; --i) {if (a[i - 2] + a[i - 1] > a[i]) {return (long long)a[i - 2] + a[i - 1] + a[i];}}return 0;
}int main() {int n;cin >> n;vector<int> a(n);for (int i = 0; i < n; ++i) {cin >> a[i];}cout << maxTrianglePerimeter(a) << endl;return 0;
}

代码解释

  1. 函数 maxTrianglePerimeter

    • 参数:vector<int>& a,存储棍子长度的数组。
    • 返回值:long long 类型的最大周长或 0
    • 首先检查数组长度是否小于 3,如果是则直接返回 0
    • 使用 sort 对数组进行排序。
    • 从数组末尾开始遍历,检查连续的三个元素是否满足三角形不等式 a[i-2] + a[i-1] > a[i]
    • 如果满足,返回这三个数的和作为周长。
    • 如果遍历结束仍未找到满足条件的三元组,返回 0
  2. 主函数 main

    • 读取输入的棍子数量 n
    • 读取 n 个棍子长度并存储在 vector<int> a 中。
    • 调用 maxTrianglePerimeter 函数并输出结果。

注意事项

  1. 数据类型

    • 使用 long long 存储周长以防止大数溢出。
    • 输入棍子长度使用 int 类型,但求和时转换为 long long
  2. 排序

    • 使用 sort 函数对数组进行排序,默认是升序排列。
  3. 边界条件

    • n < 3 时,直接返回 0
    • 当所有棍子长度相同且可以组成三角形时(如 [4, 4, 4]),返回正确的周长。

示例测试

输入 1

5
3 4 5 6 10

输出 1

21

解释:排序后为 [3, 4, 5, 6, 10],检查 5, 6, 10 满足 5 + 6 > 10,周长为 21

输入 2

4
1 2 3 5

输出 2

0

解释:排序后为 [1, 2, 3, 5],检查 2, 3, 5 不满足 2 + 3 > 5,检查 1, 2, 3 也不满足,返回 0

输入 3

3
4 4 4

输出 3

12

解释:排序后为 [4, 4, 4],满足 4 + 4 > 4,周长为 12

复杂度分析

  • 时间复杂度
    • 排序:O(n log n)
    • 遍历检查:O(n)
    • 总时间复杂度:O(n log n),满足题目要求。
  • 空间复杂度
    • 排序使用 O(1) 的额外空间(原地排序)。
    • 总空间复杂度:O(n)(存储输入数组)。

其他实现细节

  • 输入输出优化:对于大规模数据,可以使用 ios::sync_with_stdio(false);cin.tie(nullptr); 来加速输入输出。
  • 错误处理:如果输入数据不符合要求(如 n 为负数或非整数),可以添加相应的错误处理代码。

最终代码(带输入输出优化)

#include <iostream>
#include <vector>
#include <algorithm>using namespace std;long long maxTrianglePerimeter(vector<int>& a) {int n = a.size();if (n < 3) {return 0;}sort(a.begin(), a.end());for (int i = n - 1; i >= 2; --i) {if (a[i - 2] + a[i - 1] > a[i]) {return (long long)a[i - 2] + a[i - 1] + a[i];}}return 0;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin >> n;vector<int> a(n);for (int i = 0; i < n; ++i) {cin >> a[i];}cout << maxTrianglePerimeter(a) << '\n';return 0;
}

总结

通过排序和贪心策略,我们高效地解决了这个问题。C++ 的实现利用了标准库的排序函数,确保了算法的时间复杂度为 O(n log n),适用于大规模数据。代码简洁且易于理解,同时考虑了边界条件和数据类型的选择。

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

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

相关文章

【Echarts】 电影票房汇总实时数据横向柱状图比图

效果图code <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>圆角柱状图</title><script src"https://cdn.jsdelivr.net/npm/echarts5.4.3/dist/echarts.min.js"></script> </head> <…

【深度学习基础】PyTorch中model.eval()与with torch.no_grad()以及detach的区别与联系?

目录1. 核心功能对比2. 使用场景对比3. 区别与联系4. 典型代码示例(1) 模型评估阶段(2) GAN 训练中的判别器更新(3) 提取中间特征5. 关键区别总结6. 常见问题与解决方案(1) 问题&#xff1a;推理阶段显存爆掉(2) 问题&#xff1a;Dropout/BatchNorm 行为异常(3) 问题&#xff1…

博客摘录「 华为云平台-FusionSphere OpenStack 8.2.1 系统加固」2025年7月15日

编号 加固项 "风险 等级" 加固原理/Rationale 审计方法/Audit 期望结果/Expect Results 加固方法/Remediation 1 OpenSSH加固配置 1.1 OpenSSH加固配置 1.1.1 SSH使用的版本 H "Op…

永磁同步电机MTPA与MTPV曲线具体仿真实现

永磁同步电机MTPA与MTPV曲线具体仿真实现 近期做了一些标定试验&#xff0c;实际电机参数并不是确定的&#xff0c;而是变化的&#xff0c;因此很难通过解析的方法算出MTPA的对应点&#xff0c;以及在弱磁区如何过度到MTPV。这个在实际情况下都是一点点标出来的&#xff0c;我这…

Adobe Acrobat 插件功能、应用与开发

什么是 Acrobat 插件&#xff1f; Adobe Acrobat 插件是一种能够扩展 Adobe Acrobat 阅读器/查看器功能的软件组件。Acrobat 是用于查看、创建和编辑 PDF 文档的流行程序&#xff0c;而插件可以为其添加新功能&#xff0c;例如&#xff1a; #mermaid-svg-iqdM1wLkFQhd3ilQ {fon…

Redis学习系列之——高并发应用的缓存问题(二)

一、布隆过滤器布隆过滤器由一个 BitMap 和若干 Hash 函数组成&#xff0c;可以用来快速判断一个值是否存在后端存储中。它是解决 Redis 缓存穿透问题的一个不错的解决方案。工作原理步骤1&#xff1a;当 key-value 键值对存储到 Redis 后&#xff0c;向布隆过滤器添加 key步骤…

Expression 类的静态方法

public static MethodCallExpression Call(Type type, // 包含目标方法的类型string methodName, // 方法名称Type[]? typeArguments, // 泛型方法的类型参数&#xff08;非泛型方法为 null&#xff09;params Expression[]? arguments // 方…

[Nagios Core] 事件调度 | 检查执行 | 插件与进程

第五章&#xff1a;事件调度 欢迎回到Nagios Core&#xff01; 在上一章第四章&#xff1a;配置加载中&#xff0c;我们了解了Nagios如何读取配置文件以知晓需要监控的对象&#xff0c;比如我们的朋友"Web Server 1"。此时Nagios内存中已构建完整的基础设施拓扑图。…

Web3 常用前端库介绍

一、Web3 前端开发&#xff1a;连接用户与区块链的桥梁 随着 Web3 生态的蓬勃发展&#xff0c;前端开发从传统的页面渲染进化为区块链交互的核心枢纽。Web3 前端库作为连接用户与区块链的桥梁&#xff0c;承担着钱包集成、合约交互、数据可视化等关键功能。本文将系统解析主流 …

cnpm命令报internal/modules/cjs/loader.js:797 throw err; ^ Error: Cannot find

在运行一个项目的时候&#xff0c;需要升级电脑各组件的版本&#xff0c;结果导致cnpm命令无法正常使用&#xff0c;cnpm任何命令都会报如下这个错&#xff1a;找了半天&#xff0c;发现是由于cnpm与npm的版本不一致导致的&#xff0c;所以需要卸载并重新安装cnpm&#xff0c;重…

15、鸿蒙Harmony Next开发:创建自定义组件

目录 自定义组件的基本用法 自定义组件的基本结构 struct Component freezeWhenInactive build()函数 Entry EntryOptions Reusable 成员函数/变量 自定义组件的参数规定 build()函数 自定义组件生命周期 自定义组件的创建和渲染流程 自定义组件重新渲染 自定义…

深入理解Map.Entry.comparingByValue()和Map.Entry.comparingByKey()

文章目录深入理解Map.Entry.comparingByValue()和Map.Entry.comparingByKey()1. 方法定义comparingByKey()comparingByValue()2. 基本用法2.1 使用comparingByKey()2.2 使用comparingByValue()3. 方法重载版本comparingByKey(Comparator)comparingByValue(Comparator)4. 高级用…

Mac下载mysql

安装 brew list --versions | grep mysql查看已安装的mysql版本brew search mysql查看支持的mysql版本brew info mysql查看mysql版本信息brew install mysql进行安装/opt/homebrew/opt/mysql/bin/mysqld --initialize-insecure --user$(whoami) --basedir$(brew --prefix mysql…

PageHelper使用说明文档

文章目录一、简介二、集成步骤三、使用方法四、注意事项五、高级用法一、简介 PageHelper 是一个开源的 MyBatis 分页插件&#xff0c;它可以帮助我们在使用 MyBatis 进行数据库操作时方便地实现分页功能。通过简单的配置和少量的代码修改&#xff0c;就可以在查询数据时实现分…

grpo nl2sql qwen3 模型强化学习训练有效果的成立条件有哪些

在使用GRPO&#xff08;强化学习算法&#xff09;对Qwen3模型在NL2SQL&#xff08;自然语言到SQL转换&#xff09;任务上进行强化学习&#xff08;RL&#xff09;训练时&#xff0c;其效果成立的核心条件可归纳为以下几个关键维度&#xff0c;这些条件相互关联&#xff0c;共同…

面向向量检索的教育QA建模:九段日本文化研究所日本语学院的Prompt策略分析(6 / 500)

面向向量检索的教育QA建模&#xff1a;九段日本文化研究所日本语学院的Prompt策略分析&#xff08;6 / 500&#xff09; 系列说明 500 所日本语言学校结构化建模实战&#xff0c;第 6 篇。每篇拆解 1 所学校在 Prompt-QA 系统中的建模策略&#xff0c;分享工程经验&#xff0c;…

墨刀原型图的原理、与UI设计图的区别及转换方法详解-卓伊凡|贝贝

墨刀原型图的原理、与UI设计图的区别及转换方法详解-卓伊凡|贝贝最近有个设计由于时间比较仓促直接用 原型做的&#xff0c;但是原型做的大家都知道是没法用的&#xff0c;以下讲解原型和ui的区别&#xff0c;其次我们下面有三种方法把墨刀的原型变成UI图。一、墨刀原型图的原理…

前端 nodejs vue2 开发环境和微信开发环境 故障终极处理

现象某个vue2旧项目 引入vue-ls 组件等组件&#xff0c;冲突失败后删除,导致开发环境 vxe-table加载失败&#xff0c;还原后还是不行。前段项目崩溃。报警sass 某个方法 Deprecated &#xff0c;之前不会处理方式_失败回退代码项目代码 删除 node_modules&#xff0c; 删除 …

【后端】.NET Core API框架搭建(9) --配置使用Log4Net日志

目录 1.添加包 2.新建公用类 3.新建配置 4.注册 4.1.类库项目设置 5.使用 在 .NET Core 项目中使用 Log4Net 做日志记录&#xff0c;具有很多优势。尽管 .NET Core 自带了 ILogger 接口&#xff08;如使用内置的 ConsoleLogger、DebugLogger 等&#xff09;&#xff0c;但…

Agent交互细节

本文参考了https://www.bilibili.com/video/BV1v9V5zSEHA/视频及原作者代码实践 本文主要实践在第3节1、MCP MCP官方地址&#xff1a;https://modelcontextprotocol.io/introduction MCP 是一个开放协议&#xff0c;它规范了应用程序向 LLM 提供上下文的方式。 架构&#xff1a…