I am facing timeout for my solution for a HackerRank - java

I am solving a problem on hackerrank
Hacker Rank ICPC Team Problem
I have created the following code as solution for problem.
import java.math.BigInteger;
import java.util.Scanner;
public class ACMICPCTeam {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt(),count=0,maxCount=0,teams=0;
sc.nextLine();
String subjectArray[]=new String[n];
for(int i=0;i<n;i++){
subjectArray[i]=sc.nextLine();
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
String temp=""+(new BigInteger(subjectArray[i]).add(new BigInteger(subjectArray[j])));
//System.out.println(temp);
count=temp.replace("0","").length();
if(count>maxCount)
{
maxCount=count;
teams=1;
}
else if(count==maxCount)
{
teams++;
}
}
}
System.out.println(maxCount);
System.out.println(teams);
sc.close();
}
}
So what I am trying to do is I am adding the two teams subjects and I am counting non-zeros of resultant string. The highest count is number of subjects and the occurrence of highest counts are teams which know max number of subject. Even after spending a lot time I am not able to any better solution than this one still I am facing time out as it is not efficient.
I have gone through forum of the question but it was of no help.

Don't use string logic for this.
Parse the string into a BitSet, before entering your loops, i.e. as you read them.
Then use methods or(BitSet set), and cardinality().
I just completed challenge doing that. No timeouts.

Your solution is not optimal you should try something better.
You can utilize BigInteger method or BitSet class to make it easy.
For forming a team you have to use bitwise OR
Here are solutions--
// 1st approach
static int[] acmTeam(String[] topic) {
int n = topic.length;
BigInteger[] bi = new BigInteger[n];
for (int i = 0; i < n; i++)
bi[i] = new BigInteger(topic[i], 2);
int maxTopic = 0;
int teamCount = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
BigInteger iuj = bi[i].or(bi[j]);
int bitCount = iuj.bitCount();
if (bitCount > maxTopic) {
maxTopic = bitCount;
teamCount = 1;
} else if (bitCount == maxTopic) {
teamCount++;
}
}
}
int result[] = { maxTopic, teamCount };
return result;
}
// 2nd approach--using java BitSet class
static int[] acmTeamUsingBitSet(String[] topic) {
int teamCount = 0, maxTopic = 0;
int size = topic.length;
BitSet[] bitset = new BitSet[size];
for (int i = 0; i < size; i++) {
BigInteger b1 = new BigInteger(topic[i], 2);
bitset[i] = BitSet.valueOf(b1.toByteArray());
}
for (int i = 0; i < size - 1; i++) {
BitSet bitset1 = bitset[i];
for (int j = i + 1; j < size; j++) {
BitSet bitset2 = bitset[j];
BitSet tmpset = new BitSet();
tmpset.or(bitset1);
tmpset.or(bitset2);
if (tmpset.cardinality() > maxTopic) {
maxTopic = tmpset.cardinality();
teamCount = 1;
} else if (maxTopic == tmpset.cardinality()) {
teamCount++;
}
}
}
int result[] = { maxTopic, teamCount };
return result;
}
You can refer this link for a detailed video explanation.

I got good result using Java 8.
static int[] acmTeam(String[] topic) {
List<List<Integer>> res = IntStream.range(0, topic.length)
.mapToObj(s -> IntStream.range(0, topic[s].length()).boxed()
.collect(Collectors.groupingBy(i -> topic[s].charAt(i))))
.map(m -> m.get('1'))
.collect(toList());
long maxTopic = 0;
int teamCount = 0;
for (int i = 0; i < res.size(); i++) {
for (int j = i + 1; j < res.size(); j++) {
long topics = Stream.concat(res.get(i).stream(), res.get(j).stream()).distinct().count();
if (topics > maxTopic) {
maxTopic = topics;
teamCount = 1;
} else if (topics == maxTopic) {
teamCount++;
}
}
}
return new int[]{(int) maxTopic, teamCount};
}

Related

How to find most common/rare bits in a set of BitSets?

I'm working on a file sync app similar to p2p, where files are mapped by BitSets. And trying to find most rare file pieces among peers to be sent first to the receiver.
package asd;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Random;
public class ChoosePiece
{
static Random rand = new Random();
public static BitSet rand_bit_set(int size)
{
int n_long = (size + 64 -1)/64;
long a[] = new long[n_long];
for (int i = 0; i < a.length; i++) a[i] = rand.nextLong();
// clear unused bits of the last long
int m = size % 64;
a[n_long-1] <<= (64-m);
a[n_long-1] >>>= (64-m);
return BitSet.valueOf(a);
}
public static void main(String args[])
{
int n_sets = 5;
int size = 20;
System.out.println("======== receiver map ==========================");
BitSet reciever_map = rand_bit_set(size);
print(reciever_map, size);
System.out.println("======== peers maps ============================");
BitSet bs[] = new BitSet[n_sets];
for (int i = 0; i < bs.length; i++) bs[i] = rand_bit_set(size);
for (int i = 0; i < bs.length; i++) print(bs[i], size);
IdxCnt cnt[] = new IdxCnt[size];
for (int i = 0; i < cnt.length; i++) cnt[i] = new IdxCnt(i, 0);
for (int i = reciever_map.nextSetBit(0); i >= 0; i = reciever_map.nextSetBit(i+1))
{
for (int j = 0; j < bs.length; j++)
{
if (reciever_map.get(i) && bs[j].get(i)) cnt[i].cnt++;
}
if (i == Integer.MAX_VALUE) break; // or (i+1) would overflow
}
System.out.println("========== count ====================================");
System.out.println(Arrays.toString(cnt));
Arrays.sort(cnt);
System.out.println(Arrays.toString(cnt));
}
public static void print(BitSet bs, int size)
{
System.out.println(bs);
StringBuffer b = new StringBuffer();
for (int i = 0; i < size; i++)
{
char c = bs.get(i) ? '1' : '0';
b.append(c);
}
System.out.println(b.toString());
}
public static class IdxCnt implements Comparable<IdxCnt>
{
public int idx;
public int cnt;
public IdxCnt(int idx, int cnt)
{
this.idx = idx;
this.cnt = cnt;
}
#Override
public String toString()
{
return String.valueOf(cnt);
}
#Override
public int compareTo(IdxCnt o)
{
return -Integer.compare(cnt, o.cnt);
}
}
}
The above code basically counts the bits set, I wander if there is a better way to find most common/rate bits using logical operations over BitSet? Feel like there should be, could be wrong.

Finding the smallest integer that appears at least k times

You are given an array A of integers and an integer k. Implement an algorithm that determines, in linear time, the smallest integer that appears at least k times in A.
I have been struggling with this problem for awhile, coding in Java, I need to use a HashTable to find the smallest integer that appears at least k times, it also must be in linear time.
This is what I attempted but it does not pass any of the tests
private static int problem1(int[] arr, int k)
{
// Implement me!
HashMap<Integer, Integer> table = new HashMap<Integer, Integer>();
int ans = Integer.MAX_VALUE;
for (int i=0; i < arr.length; i++) {
if(table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
if (k <= table.get(arr[i])) {
ans = Math.min(ans, arr[i]);
}
}else{
table.put(arr[i], 1);
}
}
return ans;
}
Here is the empty code with all of the test cases:
import java.io.*;
import java.util.*;
public class Lab5
{
/**
* Problem 1: Find the smallest integer that appears at least k times.
*/
private static int problem1(int[] arr, int k)
{
// Implement me!
return 0;
}
/**
* Problem 2: Find two distinct indices i and j such that A[i] = A[j] and |i - j| <= k.
*/
private static int[] problem2(int[] arr, int k)
{
// Implement me!
int i = -1;
int j = -1;
return new int[] { i, j };
}
// ---------------------------------------------------------------------
// Do not change any of the code below!
private static final int LabNo = 5;
private static final String quarter = "Fall 2020";
private static final Random rng = new Random(123456);
private static boolean testProblem1(int[][] testCase)
{
int[] arr = testCase[0];
int k = testCase[1][0];
int answer = problem1(arr.clone(), k);
Arrays.sort(arr);
for (int i = 0, j = 0; i < arr.length; i = j)
{
for (; j < arr.length && arr[i] == arr[j]; j++) { }
if (j - i >= k)
{
return answer == arr[i];
}
}
return false; // Will never happen.
}
private static boolean testProblem2(int[][] testCase)
{
int[] arr = testCase[0];
int k = testCase[1][0];
int[] answer = problem2(arr.clone(), k);
if (answer == null || answer.length != 2)
{
return false;
}
Arrays.sort(answer);
// Check answer
int i = answer[0];
int j = answer[1];
return i != j
&& j - i <= k
&& i >= 0
&& j < arr.length
&& arr[i] == arr[j];
}
public static void main(String args[])
{
System.out.println("CS 302 -- " + quarter + " -- Lab " + LabNo);
testProblems(1);
testProblems(2);
}
private static void testProblems(int prob)
{
int noOfLines = prob == 1 ? 100000 : 500000;
System.out.println("-- -- -- -- --");
System.out.println(noOfLines + " test cases for problem " + prob + ".");
boolean passedAll = true;
for (int i = 1; i <= noOfLines; i++)
{
int[][] testCase = null;
boolean passed = false;
boolean exce = false;
try
{
switch (prob)
{
case 1:
testCase = createProblem1(i);
passed = testProblem1(testCase);
break;
case 2:
testCase = createProblem2(i);
passed = testProblem2(testCase);
break;
}
}
catch (Exception ex)
{
passed = false;
exce = true;
}
if (!passed)
{
System.out.println("Test " + i + " failed!" + (exce ? " (Exception)" : ""));
passedAll = false;
break;
}
}
if (passedAll)
{
System.out.println("All test passed.");
}
}
private static int[][] createProblem1(int testNo)
{
int size = rng.nextInt(Math.min(1000, testNo)) + 5;
int[] numbers = getRandomNumbers(size, size);
Arrays.sort(numbers);
int maxK = 0;
for (int i = 0, j = 0; i < size; i = j)
{
for (; j < size && numbers[i] == numbers[j]; j++) { }
maxK = Math.max(maxK, j - i);
}
int k = rng.nextInt(maxK) + 1;
shuffle(numbers);
return new int[][] { numbers, new int[] { k } };
}
private static int[][] createProblem2(int testNo)
{
int size = rng.nextInt(Math.min(1000, testNo)) + 5;
int[] numbers = getRandomNumbers(size, size);
int i = rng.nextInt(size);
int j = rng.nextInt(size - 1);
if (i <= j) j++;
numbers[i] = numbers[j];
return new int[][] { numbers, new int[] { Math.abs(i - j) } };
}
private static void shuffle(int[] arr)
{
for (int i = 0; i < arr.length - 1; i++)
{
int rndInd = rng.nextInt(arr.length - i) + i;
int tmp = arr[i];
arr[i] = arr[rndInd];
arr[rndInd] = tmp;
}
}
private static int[] getRandomNumbers(int range, int size)
{
int numbers[] = new int[size];
for (int i = 0; i < size; i++)
{
numbers[i] = rng.nextInt(2 * range) - range;
}
return numbers;
}
}
private static int problem1(int[] arr, int k) {
// Implement me!
Map<Integer, Integer> table = new TreeMap<Integer, Integer>();
for (int i = 0; i < arr.length; i++) {
if (table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
} else {
table.put(arr[i], 1);
}
}
for (Map.Entry<Integer,Integer> entry : table.entrySet()) {
//As treemap is sorted, we return the first key with value >=k.
if(entry.getValue()>=k)
return entry.getKey();
}
//Not found
return -1;
}
As others have pointed out, there are a few mistakes. First, the line where you initialize ans,
int ans = 0;
You should initialize ans to Integer.MAX_VALUE so that when you find an integer that appears at least k times for the first time that ans gets set to that integer appropriately. Second, in your for loop, there's no reason to skip the first element while iterating the array so i should be initialized to 0 instead of 1. Also, in that same line, you want to iterate through the entire array, and in your loop's condition right now you have i < k when k is not the length of the array. The length of the array is denoted by arr.length so the condition should instead be i < arr.length. Third, in this line,
if (k < table.get(arr[i])){
where you are trying to check if an integer has occurred at least k times in the array so far while iterating through the array, the < operator should be changed to <= since the keyword here is at least k times, not "more than k times". Fourth, k should never change so you can get rid of this line of code,
k = table.get(arr[i]);
After applying all of those changes, your function should look like this:
private static int problem1(int[] arr, int k)
{
// Implement me!
HashMap<Integer, Integer> table = new HashMap<Integer, Integer>();
int ans = Integer.MAX_VALUE;
for (int i=0; i < arr.length; i++) {
if(table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
if (k <= table.get(arr[i])) {
ans = Math.min(ans, arr[i]);
}
}else{
table.put(arr[i], 1);
}
}
return ans;
}
Pseudo code:
collect frequencies of each number in a Map<Integer, Integer> (number and its count)
set least to a large value
iterate over entries
ignore entry if its value is less than k
if entry key is less than current least, store it as least
return least
One line implementation:
private static int problem1(int[] arr, int k) {
return Arrays.stream(arr).boxed()
.collect(groupingBy(identity(), counting()))
.entrySet().stream()
.filter(entry -> entry.getValue() >= k)
.map(Map.Entry::getKey)
.reduce(MAX_VALUE, Math::min);
}
This was able to pass all the cases! Thank you to everyone who helped!!
private static int problem1(int[] arr, int k)
{
// Implement me!
HashMap<Integer, Integer> table = new HashMap<Integer, Integer>();
int ans = Integer.MAX_VALUE;
for (int i=0; i < arr.length; i++) {
if(table.containsKey(arr[i])) {
table.put(arr[i], table.get(arr[i]) + 1);
}else{
table.put(arr[i], 1);
}
}
Set<Integer> keys = table.keySet();
for(int i : keys){
if(table.get(i) >= k){
ans = Math.min(ans,i);
}
}
if(ans != Integer.MAX_VALUE){
return ans;
}else{
return 0;
}
}

code to find longest substring with unique K characters not working for all inputs

Given a String, ""aabbcdeeeeggi" and k=3, the code should find longest substring with maximum of k unique characters. For the above input, it should be "deeeeggi".
Here is an elegant O(n) solution for the problem in Python. I am implementing in Java. but I am not getting the desired output for all the inputs.
public class SubStringWithKUniqueCharacters {
public static void main(String[] args){
System.out.println(longestSubStringWithUniqueK("aabbcdeeeeggi", 3));
System.out.println(longestSubStringWithUniqueK("aabbcdeeeeggi", 2));
}
public static String longestSubStringWithUniqueK(String input, int k){
int len = input.length();
Set<Character> unique = new HashSet<>();
int i = 0;
int j = 0;
int count = 0;
int maxStartIndex = 0;
int maxEndIndex = 0;
int maxLen = 0;
char[] inputArr = input.toCharArray();
while (i<len){
if (count==k && j -i > maxLen){
maxStartIndex = i;
maxEndIndex = j;
maxLen = maxEndIndex - maxStartIndex;
}
if (count<k && j<len){
if (unique.add(inputArr[j])){
count++;
}
j++;
}
else {
if (unique.remove(inputArr[i])){
count--;
}
i++;
}
}
return input.substring(maxStartIndex,maxEndIndex);
}
}
Here is the output:
eeeeggi //correct output
eeeggi //incorrect output
I am not able to capture where the bug is. Any help would be much appreciated.
Thanks
Your implementation does not work the way as expected, is because the original python solution has bug. I made some modifications to your code. Hope it's now all right:
public class SubStringWithKUniqueCharacters {
public static void main(String[] args){
System.out.println(longestSubStringWithUniqueK("aabbcdeeeeggi", 3));
System.out.println(longestSubStringWithUniqueK("aabbcdeeeeggi", 2));
}
public static String longestSubStringWithUniqueK(String input, int k){
int len = input.length();
Set<Character> unique = new HashSet<>();
int i = 0;
int j = 0;
int count = 0;
int maxStartIndex = 0;
int maxEndIndex = 0;
int maxLen = 0;
char[] inputArr = input.toCharArray();
while (i<len){
if (count==k && j -i > maxLen){
maxStartIndex = i;
maxEndIndex = j;
maxLen = maxEndIndex - maxStartIndex;
}
// 1. if we reach the end of the string, we're done.
if (j + 1 > len){
break;
}
// 2. changed to count <= k here
else if (count<= k && j<len){
if (unique.add(inputArr[j])){
count++;
}
j++;
}
else {
if (unique.remove(inputArr[i])){
// 3. remove all consecutive chars of the same value
char c = inputArr[i]; // save as temp char
while (inputArr[i] == c)
{
i++;
}
count--;
}
}
}
return input.substring(maxStartIndex,maxEndIndex);
}
}
The output now is:
deeeegg
eeeegg

Parallel sort not finding the top numbers

I'm writing a program which is supposed to find the 25 top numbers in a large array using threads. My algorithm seems to work fine, however when comparing the result to an Arrays.sort-ed version of the original array, it seems like my top 25-list misses some of the numbers. I really hate posting this much code in a question, but I'm completely stuck on this, and has been for a couple of hours now. I'd love some help figuring out what's wrong. Here are my classes:
Main.java
import java.util.Arrays;
import java.util.Random;
public class Main {
public static void main(String[] args) {
final int NUM_THRS = 4;
int[] numbers = new int[500];
Random generator = new Random(500);
for(int i = 0; i < numbers.length; i++) {
numbers[i] = Math.abs(generator.nextInt());
}
Thread[] thrs = new Thread[NUM_THRS];
NumberThread[] nthrs = new NumberThread[NUM_THRS];
long startTime = System.currentTimeMillis();
for(int i = 0; i < thrs.length; i++) {
int start = getStart(i, thrs.length, numbers.length);
int stop = getStop(i, thrs.length, numbers.length);
nthrs[i] = new NumberThread(numbers, start, stop);
thrs[i] = new Thread(nthrs[i]);
thrs[i].start();
}
for (int i = 0; i < thrs.length; i++) {
try {
thrs[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int[] top = new int[25];
int[] indices = new int[NUM_THRS];
for (int i = 0; i < indices.length; i++) {
indices[i] = 24;
}
for(int i = 0; i < top.length; i++) {
top[i] = getMax(nthrs, indices);
}
for (int i = 0; i < top.length; i++) {
System.out.println(top[i]);
}
}
public static int getMax(NumberThread[] thrs, int[] indices) {
int maxNum = 0;
int maxIdx = 0;
for(int i = 0; i < indices.length; i++) {
if(indices[i] >= 0) {
if(thrs[i].topNums[indices[i]] > maxNum) {
maxNum = thrs[i].topNums[indices[i]];
maxIdx = i;
}
}
}
System.out.println("iterate");
indices[maxIdx] = indices[maxIdx]-1;
return maxNum;
}
public static int getStart(int i, int total, int len) {
return i*len/total;
}
public static int getStop(int i, int total, int len) {
if(i != total-1) {
return (i+1)*len/total;
}
return len-1;
}
}
NumberThread.java
public class NumberThread implements Runnable {
int start, stop;
int[] numbers;
int[] topNums;
public NumberThread(int[] numbers, int start, int stop) {
this.numbers = numbers;
this.start = start;
this.stop = stop;
this.topNums = new int[25];
System.out.println(start + " " + stop);
}
#Override
public void run() {
for (int i = start; i <= stop; i++) {
inner: for (int j = topNums.length-1; j > 0; j--) {
if(numbers[i] > topNums[j]) {
topNums[j] = numbers[i];
break inner;
}
}
}
}
}
The numbers printed after main are not the same as the top numbers when I Arrays.sort the numbers-array and print the top 25. Some numbers seem to be missing.
Thanks a lot in advance.
I think that your NumberThread classes Run method isn't doing what it should do. It needs to find the 25 largest numbers in the partition you assign to it, for example if the array you are searching was already sorted then the 25 largest numbers could all be in 1 partition but what its's actually doing is overwriting the first number it finds that's smaller than the current number so you end up with less than 25 numbers and they might not be the largest.
For example consider the sequence 98 99 1 2 3... 98 would get written to topNums[19] but then overwritten with 99.
I'm also not sure about the getMax function, it seems to be trying to merge the different topNums arrays together; however the arrays aren't sorted so I don't see how it can work.

Paul Erdos Conjecture [Java]

I've been trying to solve this rather easy problem on SPOJ: http://www.spoj.com/problems/HS08PAUL/.
It requires the number of prime numbers (less than n) which can be expressed in the form x^2+y^4 (where x and y are integers) to be found out.
I've whipped up a brute force solution which takes up quite a while for (n ~= 1000000), resulting in a TLE (time limit exceeded) error being thrown by the engine. Here's the source code:
import java.io.*;
import java.util.*;
class HS08PAUL {
public static int[] sieve(int n){
boolean[] prime = new boolean[n+1];
int[] primeNumbers = new int[n];
int index = 0;
Arrays.fill(primeNumbers, 0);
Arrays.fill(prime,true);
prime[0] = false;
prime[1] = false;
int m = (int)Math.sqrt(n);
for(int i = 2; i <= m; i++){
if(prime[i])
for(int k = i*i; k<=n; k+=i)
prime[k] = false;
}
for(int j = 2; j <= n; j++) {
if(prime[j]) {
primeNumbers[index] = j;
index++;
}
}
return primeNumbers;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
try{
double numberOfTestCases = in.nextDouble();
while(numberOfTestCases -- > 0) {
int index = 0, y = 0, count = 0;
int num = in.nextInt();
int[] primes = sieve(num);
while(index < num/3 ) {
for(y = 1; y < 57 ; y ++) {
if(Math.ceil(Math.sqrt(primes[index] - Math.pow(y,4))) == Math.floor(Math.sqrt(primes[index] - Math.pow(y,4)))) {
count++;
break;
}
}
index++;
}
System.out.println(count);
}
}
catch(Exception e) {
}
}
}
Is there a way in which I can make this approach work?
P.S.:Please ignore the unruly exception handling.
How many numbers of the form x^2+y^4 are there below 1000000? How many prime numbers are there below 1000000? What do these two numbers tell you about how you should approach the solution?
#isnot2bad's comment is also relevant.

Categories

Resources