leetcode题目有效三角形个数
link
题目解析:
数组中随意挑出三个数字,挑出所有可以组成三角形的组合,最终仅仅需要返回所有三元组的个数即可。
算法原理:
三角形的组成:两边之和大于第三边,两边之差小于第三边。那如果按照这种规则拿出所有的组合,再将所有组合进行判断,这个时间复杂度可能会很大,那么要减少时间的消耗,就需要先对三个数字进行排序,只需要较小的两个数字相加大于第三个数字就满足构成三角形的条件了。
优化:先对整个数组进行排序
解法一:暴力解法,三层枚举
解法二:排序之后,利用单调性,使用双指针算法来解决问题。先来固定最大的数字,这里给一个数组我们好理解,[ 2, 2, 3, 4, 5, 9, 10],
先固定第三边c=10,然后将定义两个指针,left
先从索引为0的元素开始,假设left
所在的数字数值为a,right
是C之前的索引为n-2的元素,指向第二大的元素,right
所在的数字数值为b,如果最小的元素数值跟第二大的元素数值相加大于最大的数值,那么此时2之后的元素跟9相加都会大于10,此时有right-left
组可以构成a+b>c
的三角形组合。
接下来将right--
,向前挪动一位,如果a+b
都是小于等于c的,找不到结果,然后left++
,接着重复我们上面的操作,
解法总结:
1.先固定最大的数;
2.在最大的数的区间中,使用双指针算法,快速统计出符合要求的三元组的个数;
接下来我们将思路转化成代码:
先对整个数组 进行排序,sort(nums.begin(),nums.end());
整个题目最后让我们统计出符合条件的三元组的个数,所以定义一个ret
来存储符合条件的三元组的个数,最后返回ret
即可;
接着需要利用双指针来统计符合元素的三元组,在此之前需要有一个数组中大的数字充当c,但是这个C不是固定的,让c从数组最后一个元素向前遍历到索引为2的数字,for(int i=n-1;i>=2;i--)
接着让left
指针向后遍历,right
向前遍历,
a+b>c:
如果left指向的位置的数字加上right指向的位置的数字大于c,那么从left所在位置直到right所在位置之前这一段区间的数字加上right都大于c,都满足三元组的条件,ret+=right-left
,right--;a+b<=c
:left指向位置的数字加right指向位置的数字小于c,说明left太小了,left++
;继续进行判断。最终left>=right
时结束循环。
class Solution {
public:
int triangleNumber(vector<int>& nums) {
//1.优化
sort(nums.begin(),nums.end());
//2.利用双指针解决算法问题
int ret=0;//统计三元组
int n=nums.size()-1;
//固定一个最大的数字作为c
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;
}
};