timings problems in hackerrank in “Beautiful Triplets” question - java

I am solving the "Beautiful Triplets" problem may be my logic is correct but it is showing the timings problems The Question is given below in image.My solution for same is given below. It contains only given function beautifulTriplets(int d, int[] arr) which is returning integer and accepting two values one is d and second is array of integer. Some cases are runnning but some are showing timings error.
The question is
Question
The solutions for same is
import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
public class Solution {
// Complete the beautifulTriplets function below.
static int beautifulTriplets(int d, int[] arr) {
int i,j,k,beautifulTripletsCount=0;
for(i=0;i<(arr.length-2);i++)
{
for(j=i+1;j<(arr.length-1);j++)
{
for(k=j+1;k<(arr.length);k++)
{
if(i<j&& j<k)
{
int j_i_Difference=arr[j]-arr[i];
int k_j_Difference=arr[k]-arr[j];
if(j_i_Difference==k_j_Difference && k_j_Difference==d)
{
beautifulTripletsCount++;
}
}
}
}
}
return beautifulTripletsCount;
}
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
String[] nd = scanner.nextLine().split(" ");
int n = Integer.parseInt(nd[0]);
int d = Integer.parseInt(nd[1]);
int[] arr = new int[n];
String[] arrItems = scanner.nextLine().split(" ");
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int i = 0; i < n; i++) {
int arrItem = Integer.parseInt(arrItems[i]);
arr[i] = arrItem;
}
int result = beautifulTriplets(d, arr);
bufferedWriter.write(String.valueOf(result));
bufferedWriter.newLine();
bufferedWriter.close();
scanner.close();
}
}

Your solution of 3 nested loops has a running time of O(n^3).
You can improve it to O(n^2) as follows:
Let i go from 1 to arr.length - 2. Find the number of beautiful triplets in which arr[i] is the middle element:
Iterate from i-1 down to 0 to count how many elements are equal to arr[i] - d
Iterate from i+1 up to arr.length - 1 to count how many elements are equal to arr[i] + d
Multiply the two numbers you found in the previous two steps and add the product to the total number of beautiful triplets.
This will give you a total running time of O(n^2) even if the input array is not sorted.
If the input array is sorted, you can do better, since steps 2. and 3. can be done with binary search, and therefore take O(logn) instead of O(n). This will give you a total running time of O(nlogn).
The version for general (unsorted) arrays:
int result = 0;
for (int i = 1; i < arr.length - 1; i++) {
int first = 0;
int third = 0;
for (int j = i - 1; j >= 0; j--) {
if (arr[i] - arr[j] == k) {
first++;
}
}
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] - arr[i] == k) {
third++;
}
}
result += first * third;
}

My solution to improve timing was to make one loop and find in the array the indexes j and k base on adding d to the value at position i and j. I used binarySearch implementation from java.
int count = 0;
Arrays.sort(arr);
for (int i = 0; i < arr.length; i++) {
int j = Arrays.binarySearch(arr, arr[i] + d);
if (j > 0) {
int k =Arrays.binarySearch(arr, arr[j] + d);
if (k > 0) {
count++;
}
}
}
return count;

Here is my accepted solution for BeautifulTriplets on HackerRank.
import java.util.List;
public class BeautifulTriplets {
public int beautifulTriplets(int d, List<Integer> arr) {
int size = arr.size();
int beautifulTripletsCount = 0;
for (int i = 0; i < size - 2; i++) {
for (int j = i + 1; j < size - 1; j++) {
if (arr.get(j) - arr.get(i) == d) {
for (int k = j + 1; k < size; k++) {
if (arr.get(k) - arr.get(j) == d) {
beautifulTripletsCount++;
}
}
}
}
}
return beautifulTripletsCount;
}
}
And here is the test case with 2 sample inputs.
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
class BeautifulTripletsTest {
#Test
void shouldReturnCountOfBeautifulTriplets() {
BeautifulTriplets beautifulTriplets = new BeautifulTriplets();
Assertions.assertEquals(3, beautifulTriplets.beautifulTriplets(3, Arrays.asList(1, 2, 4, 5, 7, 8, 10)));
Assertions.assertEquals(2, beautifulTriplets.beautifulTriplets(3, Arrays.asList(1, 6, 7, 7, 8, 10, 12, 13, 14, 19)));
}
}

Related

Is there a test case scenario in which my program will fail?

Problem : You have L, a list containing some digits (0 to 9). Write a function solution(L) which finds the largest number that can be made from some or all of these digits and is divisible by 3. If it is not possible to make such a number, return 0 as the solution. L will contain anywhere from 1 to 9 digits. The same digit may appear multiple times in the list, but each element in the list may only be used once.
Test Cases :
Input:
Solution.solution({3, 1, 4, 1})
Output: 4311
Input:
Solution.solution({3, 1, 4, 1, 5, 9})
Output: 94311
My Program :
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.IntStream;
public class Solution {
static ArrayList<Integer> al = new ArrayList<Integer>();
static ArrayList<Integer> largest = new ArrayList<Integer>();
static int o = 1;
static int po = 0;
static void combinations(String[] digits, String[] data, int start, int end, int index, int r)
{
if (index == r)
{
String temp = "0";
for (int j = 0; j < r; j++)
{
temp = temp + data[j];
// System.out.print(data[j]);
}
Integer d = Integer.parseInt(temp);
al.add(d);
// System.out.println(al);
}
for (int i = start; i <= end && ((end - i + 1) >= (r - index)); i++)
{
data[index] = digits[i];
combinations(digits, data, i + 1, end, index + 1, r);
}
}
static void printCombinations(String[] sequence, int N)
{
String[] data = new String[N];
for (int r = 0; r < sequence.length; r++)
combinations(sequence, data, 0, N - 1, 0, r);
}
static String[] convert(int[] x)
{
String c[] = new String[x.length];
for(int i=0; i < x.length; i++)
{
Integer k = x[i];
if(k==0)
{
o = o * 10;
continue;
}
c[i] = k.toString();
}
// System.out.println(o);
c = Arrays.stream(c).filter(s -> (s != null && s.length() > 0)).toArray(String[]::new);
po = c.length;
// System.out.println("Come"+ Arrays.asList(c));
return c;
}
public static int solution(int[] l) {
if(l.length==0)
return 0;
if(IntStream.of(l).sum()%3==0)
{
String x = "";
Arrays.sort(l);
for (int i = l.length - 1; i >= 0; i--) {
x = x + l[i];
}
return Integer.parseInt(x);
}
printCombinations(convert(l),po);
al.sort(Comparator.reverseOrder());
al.remove(al.size()-1);
al.removeIf( num -> num%3!=0);
if(al.isEmpty())
return 0;
for(int i=0; i< al.size(); i++)
{
Integer n = al.get(i);
printMaxNum(n);
}
// System.out.println(al);
// System.out.println(largest);
return largest.get(0)*o;
}
static void printMaxNum(int num)
{
// hashed array to store count of digits
int count[] = new int[10];
// Converting given number to string
String str = Integer.toString(num);
// Updating the count array
for(int i=0; i < str.length(); i++)
count[str.charAt(i)-'0']++;
// result is to store the final number
int result = 0, multiplier = 1;
// Traversing the count array
// to calculate the maximum number
for (int i = 0; i <= 9; i++)
{
while (count[i] > 0)
{
result = result + (i * multiplier);
count[i]--;
multiplier = multiplier * 10;
}
}
// return the result
largest.add(result);
}
public static void main(String[] args) {
System.out.println(solution(new int[]{9,8,2,3}));
}
}
My Code passes both given test cases and 3 other hidden test cases except one. I tried all possible input combinations but couldn't get to the exact failure. The return type by default is given as int and therefore they would not pass values which give output that does not fit in int. Any other scenario where my code fails?

Even before odd that is in ascending order using recursion

I need to be able to have an array of integers that places even integers before odd integers then sort the array in ascending order. For instance given the array [1,2,3,4,5] the final product should look like [2,4,1,3,5] as you can see the array has both the evens before the odds and then places them in ascending order.
As you see in the code I am using the array [10,9,8,7,6,5,4,3,2,1]. The output I am getting is [1,2,3,4,5,6,7,8,9,10], but this is incorrect - it should be [2,4,6,8,10,1,3,5,7,9]. I cannot use any built in functions or libraries. Here is what I have so far:
public class EBOMain {
static int[] Array = { 10,9,8,7,6,5,4,3,2,1};
static int n;
public static void main(String[] args) {
System.out.print("Array before sort: " );
for (int i = 0; i < Array.length; i++)
System.out.print(Array[i] +" ");
n = Array.length;
EvenBeforeOdd(Array, n);
int[] Array2 = new int[Array.length];
MergeSort(Array2, 0,Array.length - 1);
System.out.print("\nArray after sort: " );
for (int i = 0; i < Array.length; i++)
System.out.print(Array[i] +" ");
}
public static void EvenBeforeOdd(int []Array,int n){
if (n==0)
return;
else if(Array[n-1]%2==0) {
for(int i=0;i<n-1;i++) {
if(Array[i]%2!=0) {
int temp = Array[i];
Array[i]= Array[n-1];
Array[n-1] = temp;
EvenBeforeOdd(Array,n-1);
}
}
}
else
EvenBeforeOdd(Array,n-1);
}
static void MergeSort(int[] Combine, int LowerIndex, int UpperIndex) {
if (LowerIndex == UpperIndex){
return;
}
else { // locate Pivot
int Pivot = (LowerIndex + UpperIndex) / 2;
MergeSort(Combine, LowerIndex, Pivot);
MergeSort(Combine, Pivot + 1, UpperIndex);
Merge(Combine, LowerIndex, Pivot + 1, UpperIndex);
}
}
static void Merge(int[] Array2, int Small, int Large, int UpperIndex) {
int Pivot = Large - 1;
int LowerIndex = Small;
int n = UpperIndex - LowerIndex + 1;
int i = 0;
while (Small <= Pivot && Large <= UpperIndex)
if (Array[Small] < Array[Large])
Array2[i++] = Array[Small++];
else
Array2[i++] = Array[Large++];
while (Small <= Pivot)
Array2[i++] = Array[Small++];
while (Large <= UpperIndex)
Array2[i++] = Array[Large++];
for (i = 0; i < n; i++)
Array[LowerIndex + i] = Array2[i];
}
}
You just need to call MergeSort twice. Determine where the last even number is, call MergeSort on the even numbers, then on the odds. There should be boundary checks in case there are no even numbers (not included here):
EvenBeforeOdd(Array, n);
int lastEven = 0;
for (int i=0; i<Array.length; i++) {
if (Array[i] % 2 == 0)
lastEven = i;
}
int[] Array2 = new int[Array.length];
MergeSort(Array2, 0, lastEven);
MergeSort(Array2, lastEven+1, Array.length - 1);
Below is one of possible solutions of this problem.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Stream;
class Main {
private static final int[] array = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
public static void main(String[] args) {
List<Integer> odd = new ArrayList<>();
List<Integer> even = new ArrayList<>();
for (int number : array) {
if (number % 2 != 0)
odd.add(number);
else
even.add(number);
}
Collections.sort(odd);
Collections.sort(even);
List<Integer> evenBeforeOdd = new ArrayList<>();
Stream.of(even, odd).forEach(evenBeforeOdd::addAll);
evenBeforeOdd.forEach(System.out::println);
// 2,4,6,8,10,1,3,5,7,9
}
}

Leaders in arrays

class LeadersInArray
{
void printLeaders(int arr[], int size)
{
int max_from_right = arr[size-1];
/* Rightmost element is always leader */
System.out.print(max_from_right + " ");
for (int i = size-2; i >= 0; i--)
{
if (max_from_right < arr[i])
{
max_from_right = arr[i];
System.out.print(max_from_right + " ");
}
}
}
/* Driver program to test above functions */
public static void main(String[] args)
{
LeadersInArray lead = new LeadersInArray();
int arr[] = new int[]{16, 17, 4, 3, 5, 2};
int n = arr.length;
lead.printLeaders(arr, n);
}
}
the output of this program is 2,5,17 . MY question is can i print result in inplace manner i.e 17, 5 and then 2 (as they appear in original array) except for storing it in separate array and then traversing in reverse manner as that will add to space complexity of O(n).
Other possible solution is to use stack. Time complexity will be O(n)
import java.util.*;
import java.lang.*;
import java.io.*;
class GFG
{
public static void main (String[] args)
{
Scanner scn = new Scanner(System.in);
int tcs = scn.nextInt();
int input = 0;
int temp = 0;
List<Stack<Integer>> stks = new ArrayList<Stack<Integer>>();
for(int i=0;i<tcs;i++){
int arrSize = scn.nextInt();
Stack<Integer> stk = new Stack<Integer>();
for(int j=0;j<arrSize;j++){
input = scn.nextInt();
if(stk.empty()){
stk.push(input);
} else {
temp = stk.peek();
while(true) {
if(input>temp) {
stk.pop();
if(!stk.empty())
temp = stk.peek();
else
break;
} else {
break;
}
}
stk.push(input);
}
}
stks.add(stk);
}
for(Stack<Integer> stk: stks) {
System.out.println("");
stk.forEach(x -> System.out.print(x+ " "));
}
}
}
You can use two loop because you need to check the element after the seeing element.But the complexity is O(N*N).Not consider to be a good solution
void printLeaders(int arr[], int size) {
for (int i = 0; i < size; i++) {
int j;
for (j = i + 1; j < size; j++) {
if (arr[i] <= arr[j])
break;
}
if (j == size)
System.out.print(arr[i] + " ");
}
}
It is possible to prove that you cannot.
The only way to output the correct numbers in the order they appear in the array without using more space or increasing the algorithm complexity is by walking forward through the array.
Consider something like:
int arr[] = new int[]{16, 17, 4, 3, /* ... many more numbers */, 18, 5, 2};
Imagine you are iterating through the array and have reached the 17. The only way to know whether to print it or not is to know about the 18 further down the array. If you are only walking forward you will not know.

I am not sure why I am getting a TLE for codechef

When I submit my solution to codechef, I keep getting a time limit error. I switched to buffered reader from scanner, but that did not fix it. I'm thinking it is in my algorithm, but I am not sure where, other than checking each 5 decrement could be unnecessary. Where is the issue I am having located so that I can figure out how to solve it?
Here is the link for reference: https://www.codechef.com/problems/FCTRL
Here is my code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
class Factorial {
public static void main(String[] args) throws IOException {
BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
//how many numbers follow
int number = Integer.parseInt(keyboard.readLine());
//stores zSum's to output later
int[] answerArray = new int[number];
for(int i = 0; i < number; i++) {
//the number to compute factorial
int n = Integer.parseInt(keyboard.readLine());
// moves number to one ending in 5
n -= n % 5;
//stores number of zeros
int zSum = 0;
for (int j = n; j > 0; j -= 5) {
//if a power of 5, add 1 to zSum
for (int k = 5; k <= j; k *= 5) {
if (j % k == 0) {
zSum ++;
}
}
}
answerArray[i] = zSum;
}
//println all values in array
for (int i = 0; i < number; i++) {
System.out.println(answerArray[i]);
}
}
}
Your complexity is to high,
for (int j = n; j > 0; j -= 5)
will do O(N) operations. Inner cycle will add log to complexity.
You should write use some other approach. It can be done using O(log(N)) time for each testcase.

Fenwick Tree Java

I tried to implement the Fenwick Tree in Java, but I am not getting the desired result.
Here is my code:
import java.io.*;
import java.util.*;
import java.math.*;
class fenwick1 {
public static int N;
public static long[] a;
public static void main(String[] args)throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
a = new long[N];
String[] str = br.readLine().split(" ");
for (int i = 0; i < N; i++) {
a[i] = Long.parseLong(str[i]);
}
increment(2, 10);
System.out.println(a[2]);
System.out.println(query(4));
}
public static void increment(int at, int by) {
while (at < a.length) {
a[at] += by;
at |= (at + 1);
}
}
public static int query(int at) {
int res = 0;
while (at >= 0) {
res += a[at];
at = (at & (at + 1)) - 1;
}
return res;
}
}
When I give input:
10
1 2 3 4 5 6 7 8 9 10
I get:
13
19
So the increment function works fine. But query(4) should give the cumulative sum up to index 4 i.e.
(1 + 2 + 13 + 4 + 5) = 25
You do not initialize it properly.
Instead of:
for (int i = 0; i < N; i++) {
a[i] = Long.parseLong(str[i]);
}
It should be:
for (int i = 0; i < N; i++) {
increment(i, (int)Long.parseLong(str[i]));
}
because a[i] should store a cumulative sum, not a single element.
If you want to store the initial array elements too, you can just create one more array:
long[] initA = new long[N];
for (int i = 0; i < N; i++) {
initA[i] = Long.parseLong(str[i]);
increment(i, (int)initA[i]);
}

Categories