有效三角形的个数【双指针】

在这里插入图片描述

1.优化版暴力求解

如果能构成三⻆形,需要满⾜任意两边之和要⼤于第三边。实际上只需让较⼩的两条边之和⼤于第三边即可。将原数组排序,从⼩到⼤枚举三元组,这样三层 for 循环枚举出的三元组只需判断较⼩的两条边之和是否⼤于第三边。

class Solution
{
public:
    int triangleNumber(vector<int> &nums)
    {
        sort(nums.begin(), nums.end());

        int n = nums.size(), ret = 0;
        for (int i = 0; i < n; i++)
        {
            for (int j = i + 1; j < n; j++)
            {
                for (int k = j + 1; k < n; k++)
                {
                    if (nums[i] + nums[j] > nums[k])
                        ret++;
                }
            }
        }
        return ret;
    }
};

2.排序+二分

在 [j+1,n−1] 的下标范围内使用二分查找,找出最大的满足 nums[k]<nums[i]+nums[j]的下标 k,在 [j+1,k] 范围内的下标都可以作为边 c 的下标,将该范围的长度 k−j 累加。在枚举a和b时出现了0,那么 nums[i] 一定为 0。边c需要满足c< nums[i]+ nums[j]= nums[j],而下标在[j+1,n-1]范围内的元素一定都是大于等于 nums[j]的,因此二分查找会失败。若二分查找失败,我们可以令k=j,此时对应的范围长度k-j=0,我们也就保证了答案的正确性。

class Solution
{
public:
    int triangleNumber(vector<int> &nums)
    {
        int n = nums.size();
        sort(nums.begin(), nums.end());

        int ret = 0;
        for (int i = 0; i < n; ++i)
        {
            for (int j = i + 1; j < n; ++j)
            {
                int left = j + 1, right = n - 1, k = j;
                while (left <= right)
                {
                    int mid = (left + right) / 2;
                    if (nums[mid] < nums[i] + nums[j])
                    {
                        k = mid;
                        left = mid + 1;
                    }
                    else
                    {
                        right = mid - 1;
                    }
                }
                ret += k - j;
            }
        }
        return ret;
    }
};

3.排序+双指针

此法是对上述两种方法的优化。
排序过后数组数据为递增排列。

首先我们先来看这样一个数学常识:

将一个递增排序的数组分为两部分:
在这里插入图片描述

  1. 如果此时有Left + Right > Max 那么
    Right + Right-1
    Right + Right-2
    Right + …
    Right + Left
    的值都大于Max。那么能够构成的二元组个数为right - left个
    此时 right 位置元素的所有情况相当于全部考虑完毕, right – ,进⼊下⼀轮判断
  2. 同上,如果 nums[left] + nums[right] <= nums[i] ,说明 left 位置的元素是不可能与 [left + 1, right] 位置上的元素构成满⾜条件的⼆元组,left 位置的元素可以舍去, left++ 进⼊下轮循环。

代码

class Solution
{
public:
    int triangleNumber(vector<int> &nums)
    {
        sort(nums.begin(), nums.end());
        int ret = 0, n = nums.size();
        for (int cur = n - 1; cur >= 2; cur--)
        {
            int left = 0, right = cur - 1;
            while (left < right)
            {
                if (nums[left] + nums[right] > nums[cur])
                {
                    ret += right - left;
                    right--;
                }
                else
                    left++;
            }
        }
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿猿收手吧!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值