一. 题目描述

cpp
class Solution {
public:
int triangleNumber(vector<int>& nums) {
}
};
二. 解题思路
1)知识铺垫
- 如何判断三条边a、b、c能否构成一个有效的三角形?
① 根据我们之前的数学知识,很简单的只要任意两边之和大于第三边即可。但是用这个条件来判断需要同时满足三个条件,也就是说要判断三次,在暴力枚举的解法中对时间复杂度有不小的影响(不影响数量级)。
cpp
(a+b>c) && (a+c>b) && (b+c>a)
② 优化判断方法(只判断一次)
如果知道a、b、c的大小关系,比如 a <= b <= c,则只需要判断 a+b>c。

2)解题步骤
-
对数组进行排序。
-
利用单调性,使用双指针来解决问题:

依次固定最大值,每固定一个值,找到比他小的数字中的最大值和最小值并用双指针left和right分别标记(left指针指向的数字我们记为a,right指针指向的数字记为b,被固定的数记为c)。
此时会有两种情况 :
① a + b > c :有right-left种有效的情况,记录下来后,将right--;
原因:如果b+最小值a都已经 >c,那么b和a、b之间所有的数相加都一定 >c,都是有效的,这样一次对比就把所有固定10情况下,与9有关的有效组合找到了,此时9就没用了,我么让right指针--。
② a + b <= c :直接left++;
原因:如果a+最大值b都还 <c,那么a和a、b之间所有的数相加都一定 <c。没有有用的情况,a也没用了和他有关的都找过了。直接让left指针++。
三. 代码实现
cpp
class Solution
{
public:
int triangleNumber(vector<int>& nums)
{
int size = nums.size();
sort(nums.begin(), nums.end());
int count = 0;
int left = 0, right = 0;
// 依次固定一个最大的数
for(int i = size-1; i >= 0; i--)
{
// 左右指针利用单调性向内走
left = 0; right = i-1;
while(left < right)
{
if(nums[left] + nums[right] > nums[i])
{
count += right - left;
right--;
}
else left++;
}
}
return count;
}
};