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

[LeetCode优选算法专题一双指针——有效三角形的个数]

题目链接

LeetCode有效三角形的个数

题目描述

 

题目解析 

分析 :

首先明确计算规则:从示例 1 可以知道,对于三元组 (2,3,4) 和 (4,3,2),我们只统计了其中的 (2,3,4),并没有把 (4,3,2) 也统计到答案中,所以题目意思是把这两个三元组当成是同一个三元组,我们不能重复统计。

既然有这样的规则,那么不妨规定三角形的三条边 a,b,c 满足:

1 ≤ a ≤ b ≤ c


这可以保证我们在统计合法三元组 (a,b,c) 的个数时,不会把 (c,b,a) 这样的三元组也统计进去。

由于三角形两边之和大于第三边,我们有

  • a + b > c
  • a + c > b
  • b + c > a 

上式中的 a + c > b 是必然成立的,因为 a + c ≥ a + b > b(注意 a 至少是 1)。

同样的, b + c > a 也必然成立,因为 b+ c ≥ a+ a = 2 a > a(注意 a 至少是 1)。

所以只需要考虑第一个式子,那么问题变成,从 nums 中选三个数,满足 1 ≤ a ≤ b ≤c a + b > c 的方案数。

 

方法一:枚举最长边 + 相向双指针:

我们可以先给数组里的元素排个序,先固定一个最大的数,然后利用双指针算法结合上面讲的特性来优化算法: 

 

外层循环枚举最长边 c=nums.size(),内层循环用相向双指针枚举 a=nums[left] 和 b=nums[right],具体如下: 

初始化左右指针 left=0, right=c−1。

  • 情况一:nums[left] + nums[right] > c
  • 情况二:nums[left] + nums[right] <= c 小于和等于属于同一种情况,即不能构成三角形
  1. 单调性基础:数组经过排序后,nums[left] ≤ nums[right] ≤ nums[i]i为最大边索引)

  2. 情况一:nums[left] + nums[right] > nums[i]

  • 由于数组递增,nums[left] ≤ nums[left+1] ≤ ... ≤ nums[right-1]
  • 因此 nums[left+1] + nums[right] > nums[i]nums[left+2] + nums[right] > nums[i] ... 全部成立
  • 这意味着 [left, right-1] 范围内的所有元素与 nums[right]nums[i] 都能组成有效三角形
  • 所以直接累加 right - left 个有效组合,然后左移 right 尝试更小的中间边

    3.情况二:nums[left] + nums[right] ≤ nums[i]
     
  • 同样由于数组递增,nums[left] + nums[right-1] ≤ nums[left] + nums[right]
  • 因此当前 left 与任何 right' < right 组合都无法满足条件
  • 必须右移 left 来增大两数之和,尝试满足条件

    4.外层循环:当一组 left 和 right 判断完毕后,左移最大边索引 i,重复上述过程

完整代码 

 

 复杂度分析

时间复杂度

  1. 排序阶段
    使用 sort 函数对数组排序,时间复杂度为 O(n log n),其中 n 是数组元素个数。

  2. 双指针遍历阶段

  • 外层循环:从 i = n-1 遍历到 i = 2,共执行 O(n) 次。
  • 内层双指针:对于每个 ileft 和 right 指针在 [0, i-1] 范围内移动,两者合计移动 O(n) 次(每个元素最多被访问一次)。
  • 因此内层循环整体复杂度为 O(n)

    3.总时间复杂度:排序阶段与双指针阶段是串行执行,取量级较大的项,最终为 O(n²)

空间复杂度

  1. 排序的空间消耗
    C++ 标准库的 sort 函数通常采用快速排序(平均情况),空间复杂度为 O(log n)(递归栈开销)。

  2. 额外变量
    仅使用了 retnileftright 等有限变量,空间消耗为 O(1)

  3. 总空间复杂度
    由排序的递归栈主导,因此为 O(log n)

 

复杂度对比

  • 相比暴力枚举(三重循环,O (n³)),该解法通过排序 + 双指针将时间复杂度从立方级优化到平方级,效率提升显著。
  • 空间复杂度保持在对数级,属于高效实现。

这种复杂度特性使得该算法能处理更大规模的输入(如 n = 10^4 级别),而暴力解法在 n = 10^3 时就会出现明显性能瓶颈。

 

 

http://www.lryc.cn/news/608789.html

相关文章:

  • Python 程序设计讲义(60):Python 的函数——递归函数
  • 从“配置地狱”到“云端乐园”——Nacos 如何成为分布式微服务配置中心的“定海神针”
  • 【MySQL】MySQL中锁有哪些?
  • ethtool,lspci,iperf工具常用命令总结
  • 26李林880高数第一章 函数、极限、连续
  • Shell脚本-变量的定义规则
  • 西门子PLC基础指令4:输出指令、立即输出指令
  • JavaScript 性能优化实战指南:从运行时到用户体验的全面提升​
  • adb 与pad 交互方法
  • MyBatis动态SQL精要:从<if>到<foreach>的灵活拼接之道
  • Go语言声明变量
  • 怎么修改论文格式呢?提供一份论文格式模板
  • 【Bluedroid】btif_av_handle_event 流程源码解析
  • 面向智能体的上下文工程:策略、实现与 LangGraph 实践
  • LangChain4J入门:接入大模型
  • 系统学习算法:专题十六 字符串
  • 第三章-提示词-高级:开启智能交互新境界(13/36)
  • 日常--详细介绍qt Designer常用快捷键(详细图文)
  • 【QT】概述
  • 高质量数据集|建设三大难点
  • 01.MySQL 安装
  • 服务器中切换盘的操作指南
  • Android 之 MVVM架构
  • 使用 Docker 部署 Golang 程序
  • 第四章:OSPF 协议
  • Dify中自定义工具类的类型
  • WebMvc自动配置流程讲解
  • MySQL 索引失效的场景与原因
  • 嵌入式开发学习———Linux环境下IO进程线程学习(二)
  • 04.Redis 的多实例