Checking a triplet is triangular or not? - java

This solution of mine has 1 test failed.
https://app.codility.com/demo/results/trainingU5HYHS-MDC/
import java.util.Arrays;
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
if(A.length<3)
return 0;
Arrays.sort(A);
for(int i=0;i<A.length-2;i=i+1)
{
if( A[i]+A[i+1]>A[i+2] )
{
return 1;
}
}
return 0;
}
}
but this solution has passed 100% percent, but i cant understand why
https://app.codility.com/demo/results/trainingYKT8FB-TAV/
class Solution {
/**
* Check whether there is a triangular
* #param A The array for length of lines
* #return 0: no triangular found
* 1: triangular is found
*/
public int solution(int[] A) {
// Handle with the special cases
if(null == A || A.length < 3) return 0;
// Sort the input, and then try to find the triangular
Arrays.sort(A);
for(int i = 0; i < A.length-2; i++) {
// Beware of overflow
if (A[i] >= 0 && A[i] > A[i+2] - A[i+1]) {
return 1;
}
/*
* We already know A[i+1] <= A[i+2]. If A[i] < 0,
* A[i] + A[i+1] < A[i+2]
*/
}
return 0;
}
}

Your code fails when using 2 values that together are > than the maximum value an integer can be assigned to.
In the line if( A[i]+A[i+1]>A[i+2] ) you are making an addition. If this exceeds the integer limit you will run into an integer overflow.
The other code avoids this by never doing such an addition.

Inequality rule:
which states: the length of a side of a triangle is less than the sum of the lengths of the other two sides and greater than the difference of the lengths of the other two sides.
If we go through the sides a + b > c
if the sum of A[I] + A[I+1] larger than the capacity of int then it becomes a case of overflow, and the result of A[I] + A[I+1] < 0 => A[I] + A[I+1] not greater than A[I+2].
Here if( A[i]+A[i+1]>A[i+2] ) returns false when overflow occurs.
So, better to use,
if (A[i + 2] >= 0 && A[i + 2] > A[i + 1] - A[i])
or
if (A[i] >= 0 && A[i] > A[i+2] - A[i+1])

Related

Calculate the number of Primes that are less than the given Number [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 months ago.
Improve this question
I'm getting desired output, but I'm not able to submit the code on the Leetcode.
The link of question on the Leetcode
Problem statement:
Given an integer n, return the number of prime numbers that are
strictly less than n.
Constraints:
0 <= n <= 5 * 10 ^ 6
My code:
class Solution {
public static int count = 1;
public int countPrimes(int n) {
if (n == 0 || n == 1 || n == 2)
return 0;
else
for (int i = 3; i < n; i++) {
for (int j = 2; j < i; j++) {
if (i % j == 0) {
break;
} else if (j == i - 1 && i % j != 0) {
count++;
}
}
}
return count;
}
}
It gives the desired result all the time but when I try to submit it, it shows that only 4/66 tests cases are passed.
Can someone please tell me what's wrong here and why I'm not able to submit the solution?
Don't use static variables without any good reason. count will live in memory until the application runs and will be effected by every invocation of countPrimes() with argument n greater than 3. Even if Leetcode creates a new instance of the Solution for every test (can't check it because I'm not registered there), static variable would maintain the previously assigned value because it doesn't belong to any instances of Solution, but shared among them all.
You will definitely not encounter this issue (but potentially there could be others related to performance) if variable count would be local - i.e. declared inside the countPrimes().
Condition if (n == 0 || n == 1 || n == 2) can be simplified to if (n <= 2). And there's no need to use else clause because you are returning if condition matches.
Similarly, there's no need for the else clause in the nested loop after the break.
So your code can be written like this:
public int countPrimes(int n) {
if (n <= 2) {
return 0;
}
int count = 1;
for (int i = 3; i < n; i++) {
for (int j = 2; j < i; j++) {
if (i % j == 0) break;
if (j == i - 1 && i % j != 0) {
count++;
}
}
}
return count;
}
There are several enhancements we can make to improve performance.
Not every Number is Prime - reducing the number of iterations
As obvious, not every number is prime. The most simple observation we can make is that 2 is the only even number among primes. And if the candidate number is greater than 2 we can skip all even numbers by incrementing the index of the loop by 2.
The next interesting property of primes that we can make use of is that there's no gap between the two first primes - the next prime after 2 is 3. Which means if the candidate number is greater than 3 we don't need to check numbers that are divisible by 2 and by 3.
I.e. we can omit 4 of every 6 consecutive numbers, in other words the candidate number can be represented as N * 6 - 1 and N * 6 + 1, these pair of number will not be divisible neither by 2, no by 3.
To achieve that, we can initialize the loop variable to 6 - int i = 6 and increment it at each iteration step by 6 - i += 6, and at every step of iteration (which would represent the next range of 6 number) we need to check the candidate number against two values: i - 1 and i + 1.
Another improvement we can make is connected with condition j < i. For a large input value n this condition will cause a lot of fruitless iterations because there would be no prime divisors for any given number i greater than sqrt(i) see.
And solution will be more readable if we split the method into two logical parts based on responsibilities: a method that is responsible for checking whether a candidate number is prime, and a method that tracks the number of discovered primes.
public int countPrimes(int n) {
if (n < 3) return 0;
if (n == 3) return 1;
if (n == 4) return 2;
int count = 2;
for (int i = 6; i <= n + n % 6; i += 6) {
if ((i - 1) < n && isPrime(i - 1)) {
count++;
}
if ((i + 1) < n && isPrime(i + 1)) {
count++;
}
}
return count;
}
public boolean isPrime(int candidate) {
if (candidate % 2 == 0 || candidate % 3 == 0) return false;
if (candidate == 5) return true;
if (candidate % 5 == 0) return false;
boolean isPrime = true;
double sqrt = Math.sqrt(candidate);
for (int i = 6; i <= sqrt; i += 6) {
if (candidate % (i - 1) == 0 || candidate % (i + 1) == 0) {
isPrime = false;
break;
}
}
return isPrime;
}
This solution will be faster than the initial version, but we can do better.
Don't recalculate the same Primes
There's no need to recalculate the same prime numbers over and over while checking a candidate number.
Instead, we can store every discovered prime number into a list and then check every candidate number against the previously encountered primes from the list.
public int countPrimes(int n) {
if (n < 3) return 0;
if (n == 3) return 1;
if (n == 4) return 2;
List<Integer> primes = new ArrayList<>();
Collections.addAll(primes, 2, 3); // this line will be executed only if n > 4, hence we need to add primes 2 and 3 into the list
// we don't need variable `count` anymore, instead we can check the size of primes
for (int i = 6; i <= n + n % 6; i += 6) {
if (i - 1 < n && isPrime(i - 1, primes)) {
primes.add(i - 1);
}
if (i + 1 < n && isPrime(i + 1, primes)) {
primes.add(i + 1);
}
}
return primes.size();
}
public boolean isPrime(int candidate, List<Integer> primes) {
boolean isPrime = true;
double sqrt = Math.sqrt(candidate);
for (int i = 0; i < primes.size() && primes.get(i) < sqrt; i++) {
if (candidate % primes.get(i) == 0) {
isPrime = false;
break;
}
}
return isPrime;
}

Array, quantity of positive and negative numbers must be equal

quantity of positive and negative numbers in array must be equal.
an array mustn't contain zero.
The main issue is that array is not always consist of 50/50 of percent of positive and negative numbers.
If you can show me much simply way to code it you are welcome!
public static void main(String[] args) throws IOException {
int array[] = new int[12];
int positiveCounter = 0;
int negativeCounter = 0;
for (int i = 0; i < array.length; i++) {
array[i] = createRandom();
while (array[i] == 0) {
array[i] = createRandom();
}
if (positiveCounter > array.length / 2) {
array[i] = -1 * array[i];
positiveCounter--;
negativeCounter++;
}
if (negativeCounter > array.length / 2) {
array[i] = -1 * (-array[i]);
negativeCounter--;
positiveCounter++;
}
if (array[i] > 0) {
positiveCounter++;
}
if (array[i] < 0) {
negativeCounter++;
}
}
System.out.println(Arrays.toString(array));
System.out.println("Pos: " + positiveCounter);
System.out.println("Neg: " + negativeCounter);
}
static int createRandom() {
Random random = new Random();
int x = -10 + random.nextInt(11 - (-10));
return x;
}
The comments may lead to a very compact way to achieve your goal, but for what it is worth I'd like to explain why your code is not working as expected, and show a way that it will.
You attempt to invert the sign to keep the amount of positive and negative numbers balanced. This will work, but you have a flaw in your code. You must only invert the number if the current number needs to be inverted. If you look at this code you will see it always inverts and adjusts the counters even if array[i] is negative (in which case nothing needs to be done):
if (positiveCounter > array.length / 2) {
array[i] = -1 * array[i]; // <- This is a problem
positiveCounter--;
negativeCounter++;
}
To follow should fix your issue; the inversion is only done as needed:
for (int i = 0; i < array.length; i++) {
array[i] = createRandom();
while (array[i] == 0) {
array[i] = createRandom();
}
if (positiveCounter >= array.length / 2 && array[i] > 0) {
array[i] = array[i] * -1; // Force the number to be negative
}
if (negativeCounter >= array.length / 2 && array[i] < 0) {
array[i] = array[i] * -1; // Force the number to be positive
}
if (array[i] > 0) {
positiveCounter++;
}
if (array[i] < 0) {
negativeCounter++;
}
}

ArrayIndexOutOfBoundsException: [duplicate]

This question already has answers here:
How can I avoid ArrayIndexOutOfBoundsException or IndexOutOfBoundsException? [duplicate]
(2 answers)
Closed 7 years ago.
Help me to solve this error. This code is for Gutherine series.Consider the following algorithm
Start with a positive number n
if n is even then divide by 2
if n is odd then multiply by 3 and add 1
continue this until n becomes 1
public class Gutherine {
public static void main(String[] args) {
int a[] = {8, 3,2, 1};
int result = isGutherineSequence(a);
System.out.println(result);
}
public static int isGutherineSequence(int a[]) {
int i = 0;
int t = 0;
for (i = 0; i < 4; i++) {
if (a[i] % 2 == 0) {
if (a[i + 1] == a[i] / 2) {
t++;
}
} else if (a[i + 1] == a[i] * 3 + 1) {
t++;
}
}
if (t == 3) {
return 1;
} else {
return 0;
}
}
}
Since inside your loop you access a[i+1], you should iterate i until the next to last element, so change
for (i = 0; i < 4; i++)
to
for (i = 0; i < a.length - 1; i++)
BTW, you don't need the t counter. Once you discover that the series is not a Gutherine sequence, you can return false. You also fail to check that the last element is 1. And you should return a boolean instead of 0 or 1.
Here's a suggested implementation :
public static boolean isGutherineSequence(int a[]) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] % 2 == 0) {
if (a[i + 1] != a[i] / 2) {
return false;
}
} else if (a[i + 1] != a[i] * 3 + 1) {
return false;
}
}
return (a[a.length - 1] == 1);
}
The exception is caused by your referring to
a[i + 1]
If a[i] could be any element of the array, a[i + 1] could be one to the right of the rightmost element. So your array index would be out of bounds in that case.
The out-of-bounds exception results from your the indirection a[i + 1] even when i is odd. The loop in your isGutherineSequence function will let i reach 3 and the offending line
} else if (a[i + 1] == a[i] * 3 + 1) {
Will effectively try to extract a non-existent a[4].
You should either stop the loop at a previous spot or provide an alternate test for the last element.

Alternate positive and negative numbers in an array

Given an array of positive and negative numbers(no zeroes), I have to arrange them in such a way that the positive and negative numbers should be arranged consecutively.
The number of positive and negative numbers may not be equal i.e. if there is no positive number(or negative) left, then all the remaining negative numbers(or positive) are appended to the end of the array.
The order is important i.e.if input array is {2,-1,-3,-7,-8, 9, 5,-5,-7},then the output array should be {2,-1, 9,-3, 5,-7,-8,-5,-7}. The code is done in O(n) without using another array.
Here is my solution in java, I test it again several case and it works. However, I'm not sure if this run in O(n) time. Basically, I count the number of positive and negative number first. then I have two index i = 0 and j =1. j is always 1 step ahead i. From there I keep checking if the number in i is positive and j is negative, if it isn't, i will iterate through the array until I find the next positive/negative for the correct position and move it to the correct position.
Any suggestion is much appreciated. Thanks!
//array of negative and positive, arrange them so that positive number follow by negative
// if no pos or neg left, the rest append to the array.
//should be O(n) no additional array
public static void alter(int[] a) {
int pos = 0;
int neg = 0;
int index = 0;
while (c < a.length) {
if (a[index] > 0) {
pos++;
} else neg++;
index++;
}
int i = 0;
int j = 1;
int temp = 0;
//run until no more positive number or negative number
while (pos > 0 && neg > 0) {
//
if (a[i] > 0) {
pos--;
if (a[j] < 0) {
i += 2;
j += 2;
neg--;
} else // a[j] > 0
{
while (a[j] > 0) {
j++;
}
//a[j] < 0
neg--;
//move that number to the appropriate place
while (j > i) {
temp = a[j];
a[j] = a[j - 1];
a[j - 1] = temp;
j--;
} // end while
i += 2;
j += 2;
}
} else // a[i] < 0
{
while (a[i] < 0) {
i++;
}
//a[i] > 0
//move that number to the appropriate place
while (i > (j - 1)) {
temp = a[i];
a[i] = a[i - 1];
a[i - 1] = temp;
i--;
}
} //end else
}
}
However, I'm not sure if this run in O(n) time
I do not think it runs in O(n). The moment you have to "find the next correct element and move it to the correct location", you need to
Loop over the remainder of the array. Which means that for the worst case scenario (array with all positive elements at the start, and all negative elements at the end) you will loop for each of the positive elements one more time over half of the "unsorted" part of the array
When you move the element back to the correct location, you move it position by position. This means you loop once more over the "unsorted" part of the array
Not really sure yet how you would get it running in O(n) if you need to respect the requirement that the ordering must be respected without using a third array.
Yes, it can be done in O(n).
Lets assume that c is current position. And a[c] is positive number.
1) Increment i from c towards end of array until i points to first wrong number (number that have the same sign as previous, in this case positive).
2) Set j := i;
3) Increment j towards end of array until j points to number with wanted sign (in this case - negative).
4) Swap a[i] with a[j].
5) Set c := j;
6) Set j := c + 1;
In each step you always increment i or j or c. Never decrement.
Variable i can be incremented no more than n times. Same to j and c.
So maximum number of increments is 3n ~ O(n).
PFB my code. If we will use Stack then it will make our problem more easier.
public class AlternatePosNeg {
public static void main(String[] args) {
int arr[] = { 2, -1, -3, -7, -8, 9, 5, -5, -7 };
Stack<Integer> pos = new Stack<>();
Stack<Integer> neg = new Stack<>();
int i;
for (i = 0; i < arr.length; i++) {
if (arr[i] > 0) {
pos.push(arr[i]);
} else {
neg.push(arr[i]);
}
}
int tempArr[] = new int[arr.length];
i = 0;
int sizePos = pos.size();
int sizeNeg = neg.size();
while (i < tempArr.length) {
if (sizePos > sizeNeg) {
if (pos.size() > 0) {
tempArr[i] = pos.pop();
}
if (neg.size() > 0) {
tempArr[i + 1] = neg.pop();
i++;
}
} else {
if (neg.size() > 0) {
tempArr[i] = neg.pop();
}
if (pos.size() > 0) {
tempArr[i + 1] = pos.pop();
i++;
}
}
i++;
}
for (int no : tempArr) {
System.out.print(no + " ");
}
}
}

Determine whether or not there exist two elements in Set S whose sum is exactly x - correct solution?

Taken from Introduction to Algorithms
Describe a Θ(n lg n)-time algorithm
that, given a set S of n integers and
another integer x, determines whether
or not there exist two elements in S
whose sum is exactly x.
This is my best solution implemented in Java so far:
public static boolean test(int[] a, int val) {
mergeSort(a);
for (int i = 0; i < a.length - 1; ++i) {
int diff = (val >= a[i]) ? val - a[i] : a[i] - val;
if (Arrays.binarySearch(a, i, a.length, diff) >= 0) {
return true;
}
}
return false;
}
Now my 1st question is: Is this a correct solution? From my understanding, mergeSort should perform the sort in O(n lg n), the loop should take O(n lg n) (n for the iteration multiplied by O(lg n) for the binary search, resulting in O(2n lg n), so it should be correct.
My 2nd question is: Are there any better solutions? Is sorting the array essential?
Your solution seems fine. Yes you need to sort because its a pre requisite for binary search. You can make a slight modification to your logic as follows:
public static boolean test(int[] a, int val)
{
Arrays.sort(a);
int i = 0; // index of first element.
int j = a.length - 1; // index of last element.
while(i<j)
{
// check if the sum of elements at index i and j equals val, if yes we are done.
if(a[i]+a[j] == val)
return true;
// else if sum if more than val, decrease the sum.
else if(a[i]+a[j] > val)
j--;
// else if sum is less than val, increase the sum.
else
i++;
}
// failed to find any such pair..return false.
return false;
}
There's another very fast solution: Imagine you have to solve this problem in Java for about 1 billions integers. You know that in Java integers go from -2**31+1 to +2**31.
Create an array with 2**32 billion bit (500 MB, trivial to do on today's hardware).
Iterate over your set: if you have an integer, set corresponding bit to 1.
O(n) so far.
Iterate again over your set: for each value, check if you have a bit set at "current val - x".
If you have one, you return true.
Granted, it needs 500 MB of memory.
But this shall run around any other O(n log n) solution if you have, say, to solve that problem with 1 billion integers.
O(n).
This is correct; your algorithm will run in O(n lg n) time.
There is a better solution: your logic for calculating diff is incorrect. Regardless of whether a[i] is greater than or less than val, you still need diff to be val - a[i].
Here's an O(n) solution using a hash-set:
public static boolean test(int[] a, int val) {
Set<Integer> set = new HashSet<Integer>();
// Look for val/2 in the array
int c = 0;
for(int n : a) {
if(n*2 == val)
++c
}
if(c >= 2)
return true; // Yes! - Found more than one
// Now look pairs not including val/2
set.addAll(Arrays.asList(a));
for (int n : a) {
if(n*2 == val)
continue;
if(set.contains(val - n))
return true;
}
return false;
}
I do think I have spotted a minor bug in your implementation, but testing should uncover that one quickly.
The approach looks valid, and will reach the desired performance. You might simplify it by replacing the iterative binary search with a scan through the array, in effect replacing the binary search by a linear search that resumes where the previous linear search left off:
int j = a.length - 1;
for (int i = 0; i < a.length; i++) {
while (a[i] + a[j] > val) {
j--;
}
if (a[i] + a[j] == val) {
// heureka!
}
}
This step is O(n). (Proving that is left as an exercise for you.) Of course, the entire algorithm still takes O(n log n) for the merge sort.
A simple solution is, after sorting, move pointers down from both ends of the array, looking for pairs that sum to x. If the sum is too high, decrement the right pointer. If too low, increment the left one. If the pointers cross, the answer is no.
Your analysis is correct, and yes you must sort the array or else binary search does not work.
Here's is an alternate solution, by adding few more conditions into mergesort.
public static void divide(int array[], int start, int end, int sum) {
if (array.length < 2 || (start >= end)) {
return;
}
int mid = (start + end) >> 1; //[p+r/2]
//divide
if (start < end) {
divide(array, start, mid, sum);
divide(array, mid + 1, end, sum);
checkSum(array, start, mid, end, sum);
}
}
private static void checkSum(int[] array, int str, int mid, int end, int sum) {
int lsize = mid - str + 1;
int rsize = end - mid;
int[] l = new int[lsize]; //init
int[] r = new int[rsize]; //init
//copy L
for (int i = str; i <= mid; ++i) {
l[i-str] = array[i];
}
//copy R
for (int j = mid + 1; j <= end; ++j) {
r[j - mid - 1] = array[j];
}
//SORT MERGE
int i = 0, j = 0, k=str;
while ((i < l.length) && (j < r.length) && (k <= end)) {
//sum-x-in-Set modification
if(sum == l[i] + r[j]){
System.out.println("THE SUM CAN BE OBTAINED with the values" + l[i] + " " + r[j]);
}
if (l[i] < r[j]) {
array[k++] = l[i++];
} else {
array[k++] = r[j++];
}
}
//left over
while (i < l.length && k <= end) {
array[k++] = l[i++];
//sum-x-in-Set modification
for(int x=i+1; x < l.length; ++x){
if(sum == l[i] + l[x]){
System.out.println("THE SUM CAN BE OBTAINED with the values" + l[i] + " " + l[x]);
}
}
}
while (j < r.length && k <= end) {
array[k++] = r[j++];
//sum-x-in-Set modification
for(int x=j+1; x < r.length; ++x){
if(sum == r[j] + r[x]){
System.out.println("THE SUM CAN BE OBTAINED with the values" + r[j] + " " + r[x]);
}
}
}
}
But the complexity of this algorithm is still not equal to THETA(nlogn)

Categories