Java: How to implement subsets of a subset? - java

Following implementation finds subsets of a set, but could anyone please explain what if((i&(1<<j)) > 0) is doing and for what reason?
The comment don't seem to help out and tried console logging, yet it is still difficult to see what it is doing exactly.
//Print all subsets of given set[]
static void printSubsets(char set[]) {
int n = set.length;
//Run a loop for printing all 2^n subsets one by one
for(int i=0; i<(1<<n); i++) {
System.out.print("{ ");
//Print current subset
for(int j=0; j<n; j++) {
//(1<<j) is a number with jth bit 1
//so when we 'and' them with the
//subset number we get which numbers
//are present in the subset and which are not
if((i&(1<<j)) > 0) {
System.out.print(set[j] + " ");
}
}
System.out.println("}");
}
}
public static void main(String args[]) {
char set[] = {'a', 'b', 'c'};
printSubsets(set);
}

In a subset, each element may be either present, or not. So each element has only 2 possible states: in or out. 1 or 0. If we look at the binary representation of numbers from 0 to 2^n -1, where n is the number of elements, for example when n=3, we have:
cba
0 = 000
1 = 001
2 = 010
3 = 011
4 = 100
5 = 101
6 = 110
7 = 111
There are 8 possible subsets, and the bits represent whether an element is in the subset or not.
This is the idea used by the program:
The outer loop goes from 0 until 2^n-1.
The inner loop goes from 0 until n-1.
1<<j is 1 shifted to the left j times.
For example, when i=3, that corresponds to bits 011.
We loop from 0 until 2, comparing i against 001, 010, and 100.
For these values, the expression i & (1 << j) will be evaluated as
011 & 001 = 001, 011 & 010 = 010, and 011 & 100 = 000, respectively.
The first two are greater than 0, the last one is not.
So System.out.print(set[j] + " ") will print a and b.

Related

Counting occurrences of an array element - Index out of bounds error but the index number and out of bounds length are the same number?

So I'm having some issues with code I'm writing for an assignment and it's kinda driving me crazy. It's my first semester and I've never done coding before, so I know I still have heaps to learn. Anyways, the issues:
I'm having two problems which could be related but I'm not 100% sure. I'm getting this error:
'Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 125 out of bounds for length 125.'
Which points to the following section of code (Commented on specific line):
public static String gradesDistn() {
String gradeDistn = "0";
//Sort the above letterGrade array
Arrays.sort(letterGrade);
//This loop counts each occurrence of an element in the letterGrade array.
for (int i = 0; i < letterGrade.length - 1; i++) {
int count = 0;
for(int j = i + 1; j < letterGrade.length; j++) {
if (letterGrade[i] == letterGrade[j])
count++;
System.out.println (gradeDistn = letterGrade[i] + ": " + count); //THIS IS THE ERROR LINE.
i += (count-1);
}
}
return gradeDistn;
I can post the full code if additional context is needed. Essentially I'm am trying to count the occurrences of each letter grade (A, B, C, D, E and F) which are stored in an array. Each occurrence is based off of another array which stores number marks and is randomly generated. So the results should look something like this:
A: 6
B: 10
C:20
D: 9
E: 3
F: 1
instead I'm getting (copied from console):
A: 1
A: 2
A: 3
A: 4
B: 5
B: 6
B: 7
B: 8
B: 9
B: 10
B: 11
C: 11
C: 11
D: 11
D: 11
F: 11
C: 20
D: 9
E: 3
F: 1
I've spent so long looking at these code and trying to make it work, I feel like I'm am blind to the potentially obvious issues with it. Any help on this 2 issues would be really appreciated!
Also of note: The assignment requires a bunch of super specific methods such as this so that can't be changed, addition classes can not be used etc.
For this answer, I'm going to put aside the question of ArrayIndexOutOfBoundsException and offer guidance on how to generate a frequency distribution.
You are going to want a set of counters. Each counter will represent a range of values. To start, you should decide what range each counter will represent. Too fine a resolution, and your frequency distribution will not be very useful. For example, if your data is 100 meter sprint times for high school boys, and each counter represents an interval of 1/10,000 of a second, unless your sample size is very large, your frequency distribution would have a lot of values of '1' and '0'. You might want to separate by 1/10 of a second, 1 second, or 2 seconds, depending on how much variation there is in the boys' times.
But, if your data is species of farm animals, it would be fine to have a separate counter for each possible value.
So, determine how many counters you will need. What is the range of possible values? How closely do you want to group them?
Next, you will want a means of linking a particular value to a particular counter. In some cases, a little math can be used. In other cases, an if ... else if ... chain or a switch block is useful.
For the first example, I want to analyze daily high temperatures. I decide to group by 10 degrees Fahrenheit. I could decide on 5 degrees, 7 degrees, or some other interval. It could even be irregular intervals. But, keeping it regular and going by 10 degrees makes the example easier to follow.
Having settled on grouping by 10 degrees, I next want to decide the maximum and minimum. I'll pick -19 as the coldest, and 119 as the hottest. But, I want to allow for occurrences outside of that range. So, to hold the count, I will want an array of 15 counters.
Next, I will want a means of "translating" a temperature measurement to an array index. I use the int variable k for that in the following code. To make it easier to follow, I broke the calculation into 4 lines and then used the result as a subscript:
public static int [] tempFreqDist (WeatherStats [] daily) {
int [] count = new int [15]; // java initializes to zeros
int k;
for (int dIdx = 0; dIdx < daily.length; ++ dIdx) {
k = daily [dIdx].getHighTemp();
k = Math.max (k,-20);
k = Math.min (k,120);
k = k/10 + 2;
count [k]++;
}
return count;
}
That's it! One loop, and no sorting.
We want to group temps of -20 and colder together, regardless of how far below -20. So, we use Math.max. Similarly, we group temps of 120 and hotter by using Math.min. Next, divide by our grouping factor, and adjust the result so the lowest has 0 for the subscript value.
So, the result is the elements of count correspond to the temperature ranges: 0 ➔ -20 and colder; 1 ➔ "teens" (10 to 19) below zero; 2 ➔ single digits below zero; 3 ➔ zero and single digits above; 4 ➔ teens above zero; 5 ➔ twenties, ..., 14 ➔ teens above 100; 14 ➔ 120 and above.
But, suppose the 'width' of categories was irregular? One possibility is that you could use a chain of if ... else:
int t = daily [dIdx].getHighTemp();
if (t <= -20) k = 0;
else if (t <= -13) k = 1;
else if (t <= 0) k = 2;
else if (t <= 15) k = 3;
else if (t <= 28) k = 4;
and so on.
Another example counts animals you might see on a farm.
You can do that with an if ... else if ... chain:
public int[] animalFD (String [] species) {
int [] count = new int [6];
// 0 ➔ cattle, 1 ➔ pig, 2 ➔ sheep,
// 3 ➔ goat, 4 ➔ duck, 5 ➔ horse
...
for (int m = 0; m < species.length; ++m) {
if (species[m].equals("cow") count[0]++;
else if (species[m].equals("pig") count [1]++;
else if ...
But, for something like this, I prefer switch to if ... else chain:
public static int [] animalFD (String [] species) {
int [] count = new int [6];
for (int m = 0; m < species.length; ++m) {
switch (letterGrade [m]) {
case "cow":
count[0]++;
break;
case "pig":
count [1]++;
break;
case "sheep":
count [2]++;
break;
case "goat":
count [3]++;
break;
...
Here is a "trick" you can use to easily convert a letter to an index. Recall that a char is essentially a integer primitive: You can do numeric calculations on it.
char letter;
int idx;
...
if (letter >= 'A' && letter <= 'Z') {
idx = letter - 'A'; // result is zero to 25
...
This takes advantage of the fact that the letters A to Z are consecutive in character set encoding. However, that isn't universal. EBCDIC, for example, has non-letter characters between I and J, and between R and S, IIRC.

Code doesn't print the correct number of repeated digits

So basically this is a method to print numbers from 0 to n but squared. And to return the number of digits "d" contained in the numbers from 0 to n.
So let's say n=10 and d=1, we will have 0 1 4 9 16 25 36 49 64 81 100 and the method should return 4 since there are 4 ones in this set of numbers.
This works fine, but when n is defined with a bigger integer that's where the method starts to return an incorrect number of digits.
for instance, if we have n=5750 and d=0, the method returns 3012 when it's supposed to return 4700. Where did I do wrong?
public static int numberOfDig(int n, int d) {
String output="";
for(int i=0;i<=n;i++){
output+=(int)Math.pow(i, 2)+" ";
}
String[] numbers=output.split(" ");
String digit= Integer.toString(d);
int count =0;
for(int i=0;i<numbers.length;i++){
if(numbers[i].contains(digit))count++;
}
return count;
}
Please don't hesitate to ask questions if you need further explanations.
Your problem is that you only increment your count by one when a number contains the digit d. You need to increment by the number of times d occurs in each number.
The relevant code is:
if (numbers[i].contains(digit))
count++;
So if d == 5 and numbers[i] == 25, you increment count by 1 which is correct.
However, if d == 0 and numbers[i] == 100 you increment count by 1 which is incorrect. You should increment by 2 (as there are two zeroes).
A simple test would be n=10 and d=1, where output will be 0 1 4 9 16 25 36 49 64 81 100 121. Your method will return 5 as there are five numbers that contain a 1, whereas it should return 6 as 121 contains two instances of 1.

Java: Sum of 2D array where the M[i][j] = (int) i/j

T - number of test cases | 1<=T<=10 and n - number of elements | 1<=n<=1000000
Eg
if (T >= 1 && T <= 10) {
for (int i = 0; i < T; i++) {
int n = sc.nextInt();
if (n > 0 && n <= 1000000) {
array = new int[n][n];
System.out.print("\n" + sumOfArray(array, n));
}
}
}
Need to find the sum of M[i][j], where M[i][j] = (int) i/j;
I have written the code, but for n>10000, I start getting OOM, (for obvious reason).
If someone can help me with it, it'll be great. Need a whole new approach on solving the problem.
Eg.
Input Output
2
2 4
4 17
Here It is obvious that you don't need to store the values in the matrices because It is not possible to have that much space (Array[10000][10000]) available to allocate. So you need to think somehow in a mathematical way.
Consider a 4x4 Matrix and represent each element in the term of i,j.
1,1 1,2 1,3 1,4
2,1 2,2 2,3 2,4
3,1 3,2 3,3 3,4
4,1 4,2 4,3 4,4
Now we can represent here that what is stored in each of these elements.
1/1 1/2 1/3 1/4 (In Integers) 1 0 0 0
2/1 2/2 2/3 2/4 ============> 2 1 0 0
3/1 3/2 3/3 3/4 3 1 1 0
4/1 4/2 4/3 4/4 4 2 1 1
Tackle this matrix by dividing it into columns and solve each of the columns.
For the first column series would be 1+2+3+4.Then for the column number two(2) the series would be 0+1+1+2.
Notice here that for ith column first i-1 values are zeros and then i values are same in the column. Then value is increased. Again it will be same for i values. Again increases by 1 and so on.
So in ith column value get increased on the jth element where j%i==0.
So you can implement this logic in 1-D array and Complexity of this approach will be O(n logn) for each testcase.
Code:
import java.util.Scanner;
public class Main
{
public static void main(String args[])
{
Scanner sc=new Scanner(System.in);
int testcases=sc.nextInt();
while(testcases-- >0)
{
int n=sc.nextInt();
long array[]=new long[n+1]; //Take long array to avoid overflow
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j+=i)
{
array[j]++; //This will store that which elements get increased
//from zero how many times
}
}
//Now we can do summation of all elements of array but we need to do prefix sum here
long sum=0;
for(int i=1;i<=n;i++)
{
array[i]+=array[i-1];
sum+=array[i];
}
System.out.println(sum);
}
}
}

Trying to find the number of x's that satisfies n + x = n ^ x fails with timeout

I'm trying to solve the following problem from the section Bit Manipulation at the Hacker Rank site using new features of Java 8 such as Streams.
The problem description:
Given an integer, n, find each x such that:
0 <= x <= n
n + x = n ^ x
where ^ denotes the bitwise XOR operator. Then print an integer denoting the total number of x's satisfying the criteria above.
Constraints
0 <= n <= 1015
Sample Input: 5
Sample Output: 2
Explanation:
For n = 5, the x values 0 and 2 satisfy the conditions:
5 + 0 = 5 ^ 0 = 5
5 + 2 = 5 ^ 2 = 7
Thus, we print 2 as our answer.
Sample Input: 10
Sample Output: 4
Explanation:
For n = 10, the x values 0, 1, 4, and 5 satisfy the conditions:
10 + 0 = 10 ^ 0 = 10
10 + 1 = 10 ^ 1 = 11
10 + 4 = 10 ^ 4 = 14
10 + 5 = 10 ^ 5 = 15
Thus, we print 4 as our answer.
My code is as follows:
public class SumVsXor
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
long n = in.nextLong();
long count = LongStream.rangeClosed(0, n)
.filter(k -> k + n == (k ^ n))
.count();
System.out.println(count);
}
}
The problem is this code doesn't pass all the test cases.
It works for small values of n, but for large values such as 1000000000000000 it fails due to timeout.
I wonder whether LongStream can't handle Streams with that many elements.
The problem with your code is that it is very inefficient. For the case of n==1000000000000000, your Stream pipeline is performing 1,000,000,000,000,000 addition and XOR operations, which takes a long time. Testing for each number between 0 and n whether n + x == n ^ x would take a long time even if you use a for loop instead of Streams.
Instead of checking all the numbers between 0 and n, you should try to figure out a better way to calculate the required total number of x's. That fact that this problem appears under a "Bit Manipulation" section should give you a hint
to look into the bits of numbers that satisfy n + x == n ^ x.
Let's consider the case of n==1000000000000000. The binary representation of that large number is
0000000000000011100011010111111010100100110001101000000000000000
=== == = ====== = = = == == =
--- - - - - -- -- --- - ---------------
~~~~~~~~~~~~~~
In order for n + x to be equal to n ^ x, x must have a 0 value in all the bits corresponding with the 1 bits of n (marked with = above), and either 0 or 1 value in the bits corresponding with the 0 bits of n (marked with - above). This doesn't include the leading 0s (marked with ~ above), since x must be <= n, so any leading 0s in n must also have a 0 value in x.
This means that the total number of x's for which n + x == n ^ x is 2the number of 0s in n, not including leading 0s.
In the case of n = 1000000000000000, there are 30 such 0 bits, so the total number of x's that satisfy the requirement is 230.
Here's one way to compute the total number of x's :
long n = 1000000000000000L;
int zeroBitsCount = 0;
while (n > 0) {
if (n % 2 == 0) {
zeroBitsCount++; // counts the number of non-leading 0 bits
}
n = n >> 1; // divide n by 2 in order to examine the next bit in the next iteration
}
long total = 1L << zeroBitsCount; // the total is 2^(the 0 bits count)
I came to the same result, but via a different explanation, so thought I might post it here.
Eran's answer got to the same conclusion that I did : to modify the zeroes in the binary representation of the initial number - that is pretty straightforward.
Let's suppose our number is
101010100
so it has 5 zeroes.
you need all the possible combinations of:
a single zero
two zeroes
three zeroes
four zeroes
five zeroes
that is actually :
comb(1,5) + comb(2,5) + comb(3,5) + comb(4,5) + comb (5,5)
that is a well known formula being equal to:
pow(2,n) // where n is five in our case
from there the solution is obvious...
This is a simple question if you know little bit about XOR. I don't know much about java. But I can explain in python.
1.First convert the number to binary.
2.Count the number of zeros in that binary number.
3.print 2 ^ (number of zeros) and that's it.
Here is my python code.
n = int(input())
sum = 0
if n!=0:
n=str(bin(n))
for i in range(len(n)):
if n[i]=='0':
sum = sum + 1
print(2**(sum-1))
else: print(1)
The reason to decrement the sum by 1 is, in python it convert the number to the binary as this format. e.g: 0b'10101.
public static void main (String[] args) {
Scanner in = new Scanner (System.in);
long n = in.nextLong();
long count = 1L << (64-Long.bitCount(n)-Long.numberOfLeadingZeros(n));
System.out.println(count);
}

Maximum sub-sum

Here is example of my input data:
5 // Number of 1D arrays, in this case we'll have array[5][3]
1 2 3 // Values of array[i][0..2]
1 1 1
1 0 0
1 1 0
2 1 0
And output is:
12 // Maximum sum ({1 2 3} + {1 1 1} + {2 1 0} = {4 4 4} = 12) - END SUM VALUES MUST BE EQUAL(4 4 4).
3 // Number of arrays used to get this sum
The problem is to find maximum sum using n arrays, and secod condition is to use minimum number of arrays. Also if sum > 300 we stop algorithm. (300 is maximum). Here is my code, it's I get good answers but it's time complexity is O(2^n-1). I'm thinking that it's possible to save results in some way and don't calculate same things many times, but I don't know how yet.
public static int[] fuel(int start, int[] sum, int counter) {
int[] val = { sum[0] + crystal[start][0], sum[1] + crystal[start][1], sum[2] + crystal[start][2] };
int newSum = val[0] + val[1] + val[2];
if(newSum > 300)
return null;
if(val[0] == val[1] && val[1] == val[2]) { // All 3 values have to be equal!
if(newSum > result[0]) {
result[0] = newSum;
result[1] = counter;
} else if(newSum == result[0] && result[1] > counter) {
result[1] = counter;
}
}
if(start + 1 < crystalNumber) {
fuel(start + 1, val, counter + 1);
fuel(start + 1, sum, counter);
}
return result;
}
This may not be the best algorithm to solve this but it should be quicker than O(2^N).
The idea is to record all reachable sums as you loop through the input array. You can use a dictionary whose key is a unique hash of the possible sums, for the sake of simplicity let's just assume the key is a string which concatenates the three sums, for example, the sums [3,5,4] we'll use the key "003005004" , the value of the dictionary will be the minimum numbers of arrays to reach that sum.
So in your case:
1 2 3 => [001002003] =1
1 1 1 => [001001001] =1, [002003004]=2 (itself and use [001002003] from above)
1 0 0 => [001000000] =1, [002002003] =2, [002001001] =2, [003003004] =3
1 1 0 ...
2 1 0 ...
In the end, you will find [004004004] =3 and that's your answer.
This may seems going through all combinations as well so why it's quicker, it's because the maximum sum is 300 for each number, so in the very worst case, we may have 301^3 keys filled and have to update their values for each new input array. This is however still O(n) and despite of the large constant, it should still run much faster than O(2^n). (If you solve 300^3*n = 2^n, n is around 30-ish)
A simple hash function would be a*301*301+b*301+c
I think the problem is given m 1-D arrays and a number n, find the maximum sum using n arrays from m;
The solution looks straight forward. keep sum of each 1-D array in a separate array, say sum[]
1 2 3 = 6
1 1 1 = 3
1 0 0 = 1
1 1 0 = 2
2 1 0 = 3
Sort this array sum
6,3,3,2,1
and return the sum of first n elements of this array.

Categories

Resources