LeetCode原题链接: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
1、解题思路
本题的解题思路与同类型题【算法学习】-【双指针】-【盛水最多的容器】类似,都是通过双指针利用单调性规律进行求解,本质也是对暴力枚举的一种优化。
解题关键主要分为两部分,数学原理及双指针利用单调性,下面逐步进行说明
(1)数学原理
相信大家应该都知道三条边能否构成三角形的条件:任意两条边之和大于第三边。这里用a、b、c表示三条边,那么若a、b、c能构成三角形,则有:
a + b > c
a + c > b
b + c > a
其实我们可以对以上定理进行 “优化”:若a、b、c满足a <= b <= c
,则进行如上第一个条件a + b > c
的判断即可(因为此时c已经是最大的了),由此我们想要的单调性规律就初见雏形了
(2)利用单调性
那么根据以上结论,我们可先给数据排个序,然后 “固定”住最大的一个数(假设用一个名为end
的指针指向它),也就是排序后数组最后一个元素,把它作为c边;接着在剩余数中,设置一个指针front
指向第一个元素;另一个指针back
指向 “固定” 的那个元素的前一个元素,把它们分别作a边和b边。故此时可分为两种情况:
back
指向的那个数,已经是剩余数中最大的那个数了,故此时若 “固定 ”住a,将b向内枚举,b会越来越小,a+b的值也就越来越小,此时怎么也不可能构成三角形了。故根据单调性,此时应该将a向内枚举,a的值增大了,a+b增大,此时才有可能构成三角形。front
指针到back
指针之间的所有数都能作为a边和b边与c边构成三角形,故此时可以直接将两指针相减进行计数。这里的双指针也可叫做“对撞指针”,也就是当两个指针相遇时,一趟枚举结束;接着改变开始那个固定的最大的数,也就是c边;让end--
,其前一个数成为新的c边,开始下一轮的枚举;循环上述过程,直至end前所剩数据量<=1
。最终返回计数结果即可。
2、具体代码
int triangleNumber(vector<int>& nums)
{
sort(nums.begin(),nums.end());
int end = nums.size() - 1;
int count = 0;
while(end > 1)
{
int back = end - 1;
int front = 0;
while(front != back)
{
if(nums[front] + nums[back] > nums[end])
{
count += back - front;
back--;
}
else
{
front++;
}
}
end--;
}
return count;
看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或看不懂的地方或有可优化的部分还恳请朋友们留个评论,多多指点,谢谢朋友们!