算法挑战33: 有效三角形的个数

0 阅读2分钟

题目:

给定一个包含非负整数的数组 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个元素,计算组合数公式如下:

image.png

阶乘公式更简单:

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;
};