Problem Statement:
Given an unsorted array of positive integers. Find the number of triangles that can be formed with three different array elements as lengths of three sides of triangles.
Input: The first line of the input contains T denoting the number of testcases. First line of test case is the length of array N and second line of test case are its elements.
Output: Number of possible triangles are displayed to the user.
Constraints:
\$1 \le T \le 200\$
\$3 \le N \le 10^7\$
\$1 \le \mathrm{arr}[i] \le 10^3\$Example:
Input:
2 3 3 5 4 5 6 4 9 7 8
Output:
1 10
Algorithm:
The efficient \$O(n^2)\$ algorithm for solving this problem has been explained here.
Let \$a\$, \$b\$ and \$c\$ be three sides. The below condition must hold for a triangle (Sum of two sides is greater than the third side) i) \$a + b > c\$ ii) \$b + c > a\$ iii) \$a + c > b\$
Following are steps to count triangle.
Sort the array in non-decreasing order.
Initialize two pointers
i
andj
to first and second elements respectively, and initialize count of triangles as0
.Fix
i
andj
and find the rightmost indexk
(or largestarr[k]
) such thatarr[i] + arr[j] > arr[k]
. The number of triangles that can be formed witharr[i]
andarr[j]
as two sides isk – j
. Addk – j
to count of triangles.Let us consider
arr[i]
as \$a\$,arr[j]
as \$b\$ and all elements betweenarr[j+1]
andarr[k]
as \$c\$. The above mentioned conditions (ii) and (iii) are satisfied becausearr[i] < arr[j] < arr[k]
. And we check for condition (i) when we pickk
.Increment
j
to fix the second element again.Note that in step 3, we can use the previous value of
k
. The reason is simple, if we know that the value ofarr[i] + arr[j-1]
is greater thanarr[k]
, then we can sayarr[i] + arr[j]
will also be greater thanarr[k]
, because the array is sorted in increasing order.If
j
has reached end, then incrementi
. Initializej
asi + 1
,k
asi+2
and repeat the steps 3 and 4.
Code Implementation (in C++):
This is my implementation of the algorithm in C++ (using vectors instead of raw arrays):
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int triangles (vector<int> &V, int N);
int main () {
int T;
cin >> T;
vector<int> V;
for (int i = 0; i < T; i++)
{
int N;
cin >> N;
for (int j = 0; j < N; j++)
{
int temp;
cin >> temp;
V.push_back(temp);
}
cout << triangles (V, N) << endl;
V.clear();
}
return 0;
}
int triangles (vector<int> &V, int N)
{
int sum = 0;
sort(V.begin(), V.end());
for (int i = 0; i <= N-3; i++)
{
int k = i + 2;
for (int j = i + 1; j <= N-2; j++)
{
while (k < N && V[k] < V[i] + V[j])
k++;
sum += k-j-1;
}
}
return sum;
}
Problem:
The code gives the perfectly correct output for any input, however, when I submit the code on GeekForGeeks Practice, it says
Your program took more time than expected (Time Limit Exceeded). Expected Time Limit < 2.656sec. Hint: Please optimize your code and submit again.
At this point, I'm not sure how to optimize my code. Any ideas? Do I necessarily need to use an array instead of a vector in order to speed up the program?
The efficient O(n²) … explained here.
: document what problem is solved with what algorithm in your program source. \$\endgroup\$std::sort
. \$\endgroup\$