
目录
题目:有效三角形个数
1. 题目解析
2. 算法原理
解法一: 暴力枚举
解法二: 双指针算法
3. 代码实现
暴力枚举
双指针算法
题目:有效三角形个数
1. 题目解析
题目截图:

题目的意思就是在一个数组中,挑出的三元组,有多少个可以能构成三角形。
如何判断三角形(我们在学习数学时,早已学过的):任意两条边大于第三条边。

上面打对号的是代表可以构成三角形的,所以输出结果是3。
2. 算法原理
结合能否构成三角形的条件:

若知道a、b、c的顺序的话,就可以优化一下:只需要判断最小的两个边加起来是否大于第三个较大的边
证明:

所以,我们可以先进行对这个数组处理一下。
优化:先把这个数组排成升序(用算法库的sort函数)
解法一: 暴力枚举
先固定第一个数,然后再固定第二个数,最后再固定第三个数,判断是否构成三角形,然后再依次向后枚举。
 //伪代码演示
for (int i = 0; i < nums.size(); i++) 
    for (int j = i + 1; j < nums.size(); j++) 
        for (int k = j + 1; k < nums.size(); k++) 
            {//判断i,j,k对应的值是否构成三角形}可以看出,这个方法的时间复杂O(N³)。
解法二: 双指针算法
利用单调性,使用双指针算法来解决问题
下面举例来演示一下:


上面left和right对应的值分别是2和9,c的值是10,可以构成三角形。所以为a+b>c的情况。然后再枚举,再接着判断,这里枚举可以通过单调性优化的。
a+b>c了,那么这大于a的这一部分再与b相加肯定也是大于c的,一定是成立的,所以就可以直接让right向前移动一位,而不用right不动让left向后枚举了。那么再让它们俩相减,得出来的就是成立的个数。

所以,
① a + b > c -> right - left 种情况成立 ,再让right向前移动(right➖➖)
right向前移动一位后,然后再看新区见里有多少种情况可以构成三角形

但此时可以看到,是属于 a + b ≤ c 的情况,下面来分析一下这种情况的特点:

因为a+b已经≤c了,且这一部分≤b,那么这一部分与a相加肯定都是≤c的,所以此时a+b≤c的话,是找不到结果的。我们就让left向后移动,不再让right往前枚举判断了。
所以:
② a + b ≤ c -> left++ (left向后移动一位)
重复上面①和②过程,直到left不再小于right(它俩相遇就停止),但这仅仅是固定10的时候的所有情况找到了。再接下来固定9,继续重复上面过程,就也可以把固定9的所有成立情况找到了。
以此类推,总结:
- 先固定最大的数
- 在最大的数的左区间内,使用双指针算法,快速统计出符合要求的三元组的个数。
分析一下时间复杂度:

所以时间复杂度为O(N²)。
接下来,实现两种方法的代码。
3. 代码实现
题目链接
暴力枚举
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int ret = 0;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++) {
            for (int j = i + 1; j < nums.size(); j++) {
                for (int k = j + 1; k < nums.size(); k++) {
                    if (nums[i] + nums[j] > nums[k]) {
                        ret++;
                    }
                }
            }
        }
        return ret;
    }
};提交记录:

双指针算法
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        int ret = 0, n = nums.size();
        // 优化
        sort(nums.begin(), nums.end());
        // 利用双指针解决问题
        for (int k = n - 1; k >= 2; k--) // 先固定最大的数
        {
            // 利用双指针快速统计符合要求的三元组的个数
            int left = 0, right = k - 1;
            while (left < right) {
                if (nums[left] + nums[right] > nums[k]) {
                    ret += right - left;
                    --right;
                } else {
                    ++left;
                }
            }
        }
        return ret;
    }
};提交记录:

 制作不易,若有不足之处或出问题的地方,请各位大佬多多指教 ,感谢大家的阅读支持!!! 



















