1

Given n and an array of n positive integers, the number of ways one can choose three numbers such that they cannot form a triangle is needed.

Example:

3  
4 2 10

Answer:

1

My approach (in JAVA)

int[] arr = new int[n];//list of the numbers given
int count=0;//count of all such triplets
for(int i=0;i<n;i++)
    arr[i]=sc.nextInt();
Arrays.sort(arr);
for(int i=n-1;i>=0;i--)
{
    int j=0;
    int k= i-1;
     while(j<k && k>=0)
     {
         if(arr[i]>=arr[j]+arr[k])//condition for no triangle formation
          {
              count++;
              j++;//checking the next possible triplet by varying the third number
          }
          else if(arr[i]<arr[j]+arr[k])
          {
              j=0;
              k--;//now varying the second number if no such third number exists
          }
     }
}
System.out.println(count);

My algorithm:

After sorting the list I am trying to find all the numbers less then arr[i] such that arr[i]>=arr[j]+arr[k], in which case the triangle will not form.

But I am getting timed-out for this solution. Could anyone suggest a better approach to this problem?

yobro97
  • 1,125
  • 8
  • 23
  • 1
    I'm not quite sure I understand the algorithm you're using so you might elaborate a bit. Besides you don't need the second condition in the while loop, i.e. instead of `if(condition) { } else if (!condition) {}` just use `if(condition) { } else {}`. – Thomas Aug 17 '16 at 07:47
  • Yes....I added `if(condition) { } else if (!condition` that for better understanding..... – yobro97 Aug 17 '16 at 07:48
  • 1
    Hint: if you would be using somehow meaningful names instead of n, arr, count, and so on ... and some comments on how the algorithm is supposed to operate; maybe then other people would understand what you are doing. Or at least, they would have a chance ... you see, the idea of code is: it is **read** by humans many many many times more often than it is written. Thus you want to really really really focus on writing code that is easy to read and understand. – GhostCat Aug 17 '16 at 07:51
  • @GhostCat I have added comments for clarity.....:)... I preferred shorter names for typing comfort. Is the algo I tried clear now......? – yobro97 Aug 17 '16 at 08:01
  • It is a bit of a heavy algorithm for large `n` (O(n^2) if first glance holds), however, I don’t see you can do much better. I have never heard of getting `timed-out` in such a case, though, so you may want to explain more precisely what you are seeing, perhaps quoting an error message verbatim. PS For understanding the if-else I’d prefer putting `assert ! condition;` as first statement in the else part. – Ole V.V. Aug 17 '16 at 08:10
  • @yobro97 Any decent IDE does auto-completion nowadays; so don't call it "comfort", but laziness ;-) And now, your comments do not really help. They just say WHAT is there, and the WHAT one can see in the code. Comments should be made to explain the WHY you do something; describe the intent behind actions. – GhostCat Aug 17 '16 at 08:14
  • @OleV.V. seems more like `O(n^3)` – Yerken Aug 17 '16 at 08:16
  • Does it run nicely for small `n`? – Ole V.V. Aug 17 '16 at 08:25
  • @yobro97 if you find my answer useful, please mark it as solution. We'll both receive reputation and the answer will be more reliable to other users. – xenteros Sep 21 '16 at 10:41

2 Answers2

3

The appropriate pseudo-code would be:

SORT array //nlogn
INT counter = n*(n-1)*(n-2)/6;
FOR i = n - 1; i >= 2; i-- DO //largest length in a triangle - there must be two lower
    currentLargestNumber = array[i];
    FOR j = i - 1; j >= 1; j-- DO
        BINARY SEARCH FOR SMALLEST k for which array[k] + array[j] > array[i]
        counter -= j - k;
        IF nothingAddedInTheLastIteration DO
            BREAK;
        END_IF
    END_FOR
    IF nothingAddedInTheLastIteration DO
        BREAK;
    END_IF
END_FOR

I assumed that there won't be input with more then 3 identical values. If there is such possibility remove unnecessary values.

In each loop you should check if any triangle was added. If not, break this loop.

xenteros
  • 15,586
  • 12
  • 56
  • 91
1

The problem can be solved using two pointer technique, but instead of counting how many triplets cannot form a triangle, we will look for the opposite and at the end subtract the result from C(n,3) = (n)(n-1)(n-2)/6. Let's sort the array arr, arr[0] < arr[1] .. < arr[n-1]. And for a given pair i < j find index k > j, s.t. arr[i] + arr[j] <= arr[k] and arr[i] + arr[j] > arr[k-1]. This will result in additional k - j -1 triplets (triplets are : {i,j,j+1},{i,j,j+2},..,{i,j,k-1}. Now notice that whenever we increase j, we don't need to reset the value of k, which helps to keep the total time complexity O(n^2).

//arr is already sorted
long triangles = 0;
for(int i = 0; i < n-2; i++){
   int k = i + 2;
   for(int j = i + 1; j < n; j++){
      while(arr[i] + arr[j] > arr[k] && k < n){
         k++;
      }
      triangles += k-j-1;
   }
} 
long answer = n*(n-1)*(n-2)/6 - triangles;
Yerken
  • 1,944
  • 1
  • 14
  • 18