leetcode刷题/每日一题 611. 有效三角形的个数

611. 有效三角形的个数

题意:

给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。

示例 1:

输入: [2,2,3,4]
输出: 3
解释:
有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3
解题思路:

我的想法是这样的,用双指针(定二动一),左边指向第一个节点,右边指向最后一个节点,然后一个滑标 从右边出发,知道左边加上滑标的值小于最后的大的.加上下标的差,然后左边+1,重复上面循环直到左边和右边相差1.

构思用双指针,左边指向第一个节点,右边指向最后一个节点.然后定义一个滑标
什么时候结束滑动?左指针的值加上滑动的值小于右指针的值(两边之和大于第三边),就可以获得下标差.
这样一个个算的时间复杂度太大了,有两层循环还要一个个比较?因为只需要找到一个值使得两边之和小于第三边即可,所以可以用二分查询第一个小于等于的值即可,
怎么查找第一个小于等于的值?可以自己写一个函数判断,也可以直接用lower_bound()函数
细节**注意寻找值时左边是从左指针+1开始的,不能一条边取两次 ; 因为函数找的是大于等于,而两边之和大于第三边,那么就需要边差值 +1 **
  • 到这里基本就可完成问题,遍历全部数组可以组的双指针,然后找第一个大于等于右边-左边的值,然后加上下标差即可
代码:
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
    //如果边数小于3条,不可能组成
    if(nums.size() < 3)
        return 0;        
    //先排序
    sort(nums.begin(),nums.end());
	int res = 0;
    //获得最左边的值
	vector<int>::iterator left = nums.begin();
	vector<int>::iterator right = --nums.end();

    //第一层循环,左边到最后的边要大于3条,
	while (left != nums.end() - 2)
	{
        //左边需要+1才是找的范围
		vector<int>::iterator left_round = left + 1;
        //第二次循环,找每一个值
		while (right - left > 1)
		{
            //找第一个大于等于的值,但是两边之和要大于第三步,所以需要 +1
			auto it = lower_bound(left_round, right, *right - *left + 1);
            //下标差就是个数
			res += right - it;
			right--;
		}
        //外层循环继续
		left++;
		right = --nums.end();

	}
	return res;
    }
};


第二种

第一种的时间复杂度太高,为O(n2 log2n) ,那么需不需要更快的呢.这时候就想到另外的办法,

解题思路

还是利用双指针,但是定一滑二.

定一遍历数组,从最后开始到第三个数值结束
滑二一个从开始位置,一个从定一的上一位开始
怎么获得结果?如果滑二的两个值之和大于定义,就获取它的下标差.如果不是就让左边+1(这样才能让边更大). 直到相加大于定一为止
  • 大体思路就完成了,每个值只需要比较滑二即可.代码如下
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
    //个数小于3个,直接返回
    if(nums.size() < 3)
        return 0;
    //先排序
	sort(nums.begin(), nums.end());
    //最后一个值
	int end = nums.size() - 1;
    int res = 0;
	//遍历全部数组,定一
	for (int right = end; right >= 2; --right)
	{
        //滑二
		int i = 0;
		int j = right - 1;
		while (i < j) 
		{
            //如果两边之和大于第三边,直接加下标差
			if (nums[i] + nums[j] > nums[right])
			{
				res += j - i;
				j--;
			}
            //如果小于就缩小范围
			else 
				i++;
		}
	}
	return res;
    }
};
总结:

建议使用第二种,时间复杂度最差的情况为O(n2),但是基本达不到这种最坏情况.所以时间快第一种很多.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

公仔面i

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

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

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

打赏作者

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

抵扣说明:

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

余额充值