题目:
给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。
思路:
三角形的两边之和大于第三边
我们只要让任意两条边之和大于最长边就好了
所以我们枚举最长边
先排序,然后倒着遍历数组,最长边的索引是 len - 1;
剩下两个边可以用相向双指针进行求解
a是0, b是c-1
如果nums[a] + nums[b] > nums[c],那么 从a到b-1的元素与 nums[b] 的和都是大于nums[c] 的
我们就给count 加上 b - a , 并且 b--;
如果nums[a] + nums[b] < nums[c], 那么 从 a+1 到 b 的元素与 nums[a] 的和都是小于
nums[c] 的
我们就给 a++;
在循环结束后,返回count;
另外添加了两个优化,
第一个是最小的两个边和最长的边相比,如果大于最长边的话,那后面的都是大于的,我们直接把len 中取 3 的组合数 加给count,然后返回就好了
什么?你问我组合数怎么算?
我贴个图
从n个元素中依次选出m个元素,计算组合数公式如下:
阶乘公式更简单:
n! = n * n-1 * n-1 * ... * 1
第二个优化是
最长的两条边之和 小于 最长边 ,说明 这一个外循环没有一个组合符合,因为剩下的前两条边都更小
不可能比第三条边大
代码:
var triangleNumber = function (nums) {
let count = 0;
let len = nums.length;
nums.sort((a, b) => a - b);
//枚举最长边
for (let c = len - 1; c > 1; c--) {
//优化一
if (nums[0] + nums[1] > nums[c]) {
count += (c + 1) * c * (c - 1) / 6;
break;
}
//优化二
if (nums[c - 2] + nums[c - 1] <= nums[c]) continue;
let a = 0;
let b = c - 1;
while (a < b) {
if (nums[a] + nums[b] > nums[c]) {
count = count + b - a;
b--;
} else {
a++;
}
}
}
return count;
};