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

【双指针】专题:LeetCode 611题解——有效三角形的个数

有效三角形的个数

  • 一、题目链接
  • 二、题目
  • 三、算法原理
    • 1、判断是否是三角形的方法
    • 2、解法
  • 四、时间复杂度
  • 五、编写代码

一、题目链接

有效三角形的个数

二、题目

在这里插入图片描述

三、算法原理

1、判断是否是三角形的方法

常规方法:三条边分别是a、b、c,要同时满足a + b > c、a + c > b、b + c > a才能构成三角形,但是要判断三次。

优化方法:仅需判断一次。已知三条边的大小顺序a <= b <= c(说明要提前对数组里的数据排好序),只要两个较小边之和大于最大一条边c就能构成三角形:a + b > c。优化后的方法相较于上面的普通方法少判断了a + c > b、b + c > a,不用判断的理由是c已经是最大边了,肯定有c >= a、c >= b,这样c再加上a肯定大于b,同理,c再加上b肯定大于a。

2、解法

解法一:暴力枚举。

三层for循环分别固定三个数。(伪代码:看懂就行,只是个思路,不能作为最终代码提交。)

在这里插入图片描述

若选择常规方法判断是否是三角形,时间复杂度是O(3n^3),前面的3表示判断三次;若选择优化方法判断是否是三角形,先对数组排好序,时间复杂度是O(nlogn + n^3)(nlogn是排序算法的时间复杂度,因为只需判断一次,所以是n^3)。提升点1:3n^3 > nlogn + n^3,优化方法对暴力枚举的时间复杂度提升非常大。

提升点2:优化后,数组已经有序,可以利用已经有序的单调性作很多的优化。

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

步骤:

  1. 数组已有序(升序),固定最大数c
  2. 在最大数c的左区间内,使用双指针算法,快速统计出符合要求的三元组的个数
  3. 情况1:a + b > c,right - left,right - -。情况2:a + b <= c,left++

分析过程:

数组已有序(升序),先固定最大数c,再枚举剩下的两个数a、b。不是胡乱枚举,要不时间复杂度又是O(n^3)了。

找最大数c的左区间内的最小值和最大值(分别对应左区间中的第一个数和最后一个数),分别用指针left、right指着。

在这里插入图片描述

所以,只有两种情况:情况1:a + b > c 情况2:a + b <= c

2 + 9 > 10中了情况1,说明构成三角形。left和right中间这些数都 >= 当前left指向的数,那么这些数与right指向的数相加肯定大于c,肯定都满足构成三角形的条件,这一下子就有5个有效三角形的个数(个数求法:下标相减right - left):
在这里插入图片描述

因为9与这些数相加都大于c,所以9用完了,可以right - -。计算新区间中组成三角形三条边的三元组个数:
在这里插入图片描述
2 + 5 < 10中了情况2,不满足三角形的条件,当前left和right中间这些数都小于right所指,那么这些数与left所指相加肯定也 <= c(别的示例有等于的情况),这样就不用计算,直接left++:

在这里插入图片描述
直到两个指针相遇,结束计算。把最大数换成9,再在9的左区间找最大值和最小值,重复过程。把所有数都固定完一遍就能得到结果。

在这里插入图片描述

画图分析到最后发现c在下标为1处时就没有必要再计算了。在下标为0处就更没有必要了。其实写成 i >= 0也没有关系,写成上面分析的样子更标准一点:

在这里插入图片描述

四、时间复杂度

分析解法二的时间复杂度:

数组已有序(升序),固定最大数c,从右向左每一个数都可以成为固定的最大数c,那就是O(n)。两个双指针相向移动,遍历一遍数组就可以计算出三角形个数,也是O(n)。循环嵌套,O(n^2),该解法比优化后的暴力枚举还要好。

五、编写代码

不要在for循环外面定义left、right,因为在循环内部会改变它们的。是每次固定完一个数之后才出现一个左右区间,所以双指针要定义在循环内部。

if里有多个语句想偷懒写成一行,语句中间记住是用逗号分隔开,用分号分隔会导致if语句断掉。

class Solution {
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(), nums.end());int sum = 0, n = nums.size();for (int i = n - 1; i > 1; --i){int left = 0, right = i - 1;while (left < right){if ((nums[left] + nums[right]) > nums[i]) sum += (right - left), right--;else left++;}}return sum;}
};

相关文章:

  • OpenCV 图形API(39)图像滤波----同时计算图像在 X 和 Y 方向上的一阶导数函数SobelXY()
  • 企业采购平台搭建指南:从流程重构到生态协同的数字化转型路径
  • 【学习笔记】Taming 3DGS泛读
  • 【android bluetooth 协议分析 02】【bluetooth hal 层详解 1】【uart 介绍】
  • 【病毒分析】定向财务的钓鱼木马分析
  • 过滤器及拦截器
  • 一文掌握RK3568开发板Android13挂载Windows共享目录
  • C++Cherno 学习笔记day21 [86]-[90] 持续集成、静态分析、参数计算顺序、移动语义、stdmove与移动赋值操作符
  • 蓝桥杯 8. 分巧克力
  • oracle判断同表同条件查出两条数据,根据长短判断差异
  • leetcode_344.反转字符串_java
  • CS5346 - CHARTS: Chart with Point / Bar / Line / Box
  • matlab中simulink的快捷使用方法
  • 用友U8在参照生产订单界面显示各个仓别的可用量
  • 机器学习03——K近邻
  • 【漫话机器学习系列】204.不确定性的来源(Sources Of Uncertainty)
  • 算力狂飙时代:解码2024年上海及周边区域IDC市场的三重构局
  • 神经网络模型应用到机器学习时的难点
  • 4.16学习总结
  • 数据中台(大数据平台)之数据资源目录
  • 微信网站需要备案吗/by网站域名
  • 公司网站做的很烂/产品如何做网络推广
  • 网站建设怎么报印花税/网站及搜索引擎优化建议
  • 做网站域名有什么用/百度关键词点击价格查询
  • java 做网站 模板在哪可以下/app推广工作是做什么的
  • 聊城做网站建设的公司/百度一直不收录网站