三角形个数

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

int triangleNums(vector<int> triangleVecs)
{
	int ans = 0;
	//思路分析
	//1.先将原来的vector从小到大排序
	sort(triangleVecs.begin(), triangleVecs.end());

	//2.三条边,两个小边之和大于第三边怎可以拼成三角形
	//即如果a <= b <= c且a + b > c 那么a b c三条边能拼成三角形
	//因为假如a <= b <= c 且 a + b > c
	//那么必定有:a + c > b  b + c > a
	//从而又有a > c - b  b > a - c 
	//又因为a <= b <= c所以c > b - a;
	//所以有结论任意两边之和大于第三边,任意两边之差小于第三边,
	//所以如果a <= b <= c且a + b > c 那么a b c三条边能拼成三角形

	//3.循环确定两边,寻找可以拼成三角形的第三边,直到找到从小到大的数列中第一个拼不成三角形那条边的下标
	//根据这个下标确定出能拼成三角形的三角形个数

	//外层循环是第一个边,最远遍历到3, 3, 5, 6, 7, 8 的6所在的位置,即最远遍历到vec的倒数第三个元素
	for (int i = 0; i < triangleVecs.size() - 2; i++)
	{
		//外层循环是第二个边,要从第一条边的后面开始,最远遍历到3, 3, 5, 6, 7, 8 的7所在的位置,
		//即最远遍历到vec的倒数第二个元素
		for (int j = i + 1; j < triangleVecs.size() - 1; j++)
		{
			int sum = triangleVecs[i] + triangleVecs[j];
			//在left到right范围内寻找可以拼成三角形的第三边,
			int left = j + 1;//紧挨第二条边的后面一个边开始寻找
			int right = triangleVecs.size() - 1;//最后一个元素

			//通过二分法开始寻找
			while (left <= right)
			{
				int mid = left + (right - left) / 2;

				if (sum > triangleVecs[mid])
				{
					//两边之和大于第三边,可以拼成三角形,那么
					//从left到mid的元素,都可以与那两边拼成三角形
					//此时从mid后面继续寻找更多的可以拼成三角形的元素
					left = mid + 1;
				}
				else if (sum <= triangleVecs[mid])
				{
					//两边之和小于等于第三边,拼不成三角形,那么
					//从mid到right的元素,都不可以与那两边拼成三角形
					//此时从mid前面继续寻找可以拼成三角形的元素
					right = mid - 1;
				}
			}

			//循环退出后,此时left在了right的前面一个元素,即left = right + 1;
			//那么这个时候,通过实际画图去分析,可以知道,right与j + 1 之间的
			//边是可以与另外两个边组成三角形的元素
			//所以这一轮二分查找得到的与确定的两条边可以组成的三角形个数等于 right - (j + 1) + 1 个 
			if (sum > triangleVecs[right])
			{
				int nums = right - (j + 1) + 1;
				ans += nums;
			}
		}
	}
	return ans;
}

int main()
{
	vector<int> triangleVecs = { 3, 3, 5, 6, 7, 8 };
	int result = triangleNums(triangleVecs);
	cout << result << endl;

	vector<int> triangleVecs2 = {2, 2, 3, 4 };
	result = triangleNums(triangleVecs2);
	cout << result << endl;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值