目录
题目:有效三角形个数
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;
}
};
提交记录:
制作不易,若有不足之处或出问题的地方,请各位大佬多多指教 ,感谢大家的阅读支持!!!