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