Java HashSet (Long vs Integer) - java

I was solving this problem, (41 from Project Euler), where I noticed that contains method of HashSet is working differently for Long as compared to Integer (I might be wrong here, please correct me if I am).
The question is -
We shall say that an n-digit number is pandigital if it makes use of
all the digits 1 to n exactly once. For example, 2143 is a 4-digit
pandigital and is also prime.
What is the largest n-digit pandigital prime that exists?
My code for checking whether the number is Pandigital or not is -
private static boolean isPan(Long n) {
HashSet<Long> list = new HashSet<Long>();
int count = 0;
while(n != 0){
list.add(n%10);
count++;
n /= 10;
}
for(int i = 9; i>count; i--){
if(list.contains(i)) return false;
}
for(int i = 1; i<= count; i++){
if(!list.contains(i)) return false;
}
return true;
}
This code gave me an infinite loop. So, I changed my code like this -
private static boolean isPan(Long n) {
HashSet<Integer> list = new HashSet<Integer>();
int count = 0;
while(n != 0){
list.add((int) (n%10));
count++;
n /= 10;
}
for(int i = 9; i>count; i--){
if(list.contains(i)) return false;
}
for(int i = 1; i<= count; i++){
if(!list.contains(i)) return false;
}
return true;
}
I just changed, HashSet<Long> to HashSet<Integer> and list.add(n%10) to list.add((int) n%10).
This gave me the correct answer, 7652413. So, can anyone explain why the contains method works differently for Long when compared to Integer?

contains(Object o) method doesn't work different for Long vs Integer. It works exactly the same, i.e.
Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).
Notice however that method accepts Object as parameter type, not E. That means you can call it with any type of object. Of course, any object type other than E would cause it to return false, since equals() would fail for objects of different types (with some exceptions).
So, when you call contains(x), and x is a primitive, it will be auto-boxed, based on the type of x, not on the type of E. So if x is an int and E is Long, it'll always return false.
It is not contains() that suddenly works different, when you change Long to Integer. It is your code that works different, by correctly matching the type of value passed to contains() to the type of elements in the collection.
UPDATE
Your code is not very efficient:
It takes a Long as a parameter, but max n is by nature 9, and and int can store 9-digit numbers without overflow, so use of Long, and use of boxing, is unnecessary.
It allocates a new HashSet for every value being checked, and autoboxes every digit found, plus 9 times for the contains() calls.
Instead, this can be done using bit-manipulation, since as 32-bit int value can easily store 10 boolean values (flags) indicating whether a digit was present.
The code below will establish two bit-masks, found and expected, which will indicate whether a digit is found, and whether a digit was supposed to be found. Since solution should only use digits 1-n, we'll claim digit 0 is present and expected (makes logic simpler, not having to do special checks for 0).
If a digit is presented twice (or digit 0 is presented once), another expected digit will be missing, and found will not equal expected.
private static boolean isPandigital(int number) {
int found = 1, expected = 1;
for (int n = number; n != 0; n /= 10, expected = (expected << 1) | 1)
found |= 1 << (n % 10);
return (found == expected);
}

If you want your code run correctly,see your code whose list is HashSet<Long>:
for(int i = 1; i<= count; i++){
if(!list.contains(i)) return false;
}
you can change the type of variable i to long,or change if(!list.contains(i)) return false; to the if(!list.contains(Long.valueOf(i))) return false;
Because of the contains will check element in existence by the element's method equals.In above code,the variable i is auto-boxed to Integer instance,because the variable i is primitive int.
And see the Integer equals:
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
but your list element's type is Long,so the line if(!list.contains(i)) return false; will return false always.

Related

How to calculate the number of zeros in binary?

Hi I am making a method that can take an integer as a parameter and compute how many zeros its binary form has. So for example, if I have binaryZeros(44), its binary form is 101100. Therefore, binaryZeros(44) should return 3. However, I am making some errors and I cannot tell where it is coming from. I would appreciate it if someone can point out where I am making that error, or if my approach (logic) to this problem is good enough. Thank you!
My code is Below:
public static int binaryZeros(int n) {
int zeroCount = 0;
double m = n;
while (m >= 0.0) {
m = m / 2.0;
if (m == Math.floor(m)) {
zeroCount++;
} else {
m = Math.floor(m);
}
}
return zeroCount;
}
Below is a more concise way to solve this problem
public static int binaryZeros(int n) {
int zeroCount = 0;
// Run a while loop until n is greater than or equals to 1
while(n >= 1)
{
/* Use modulo operator to get the reminder of division by 2 (reminder will be 1 or 0 as you are dividing by 2).
Keep in mind that binary representation is an array of these reminders until the number is equal to 1.
And once the number is equal to 1 the reminder is 1, so you can exit the loop there.*/
if(n % 2 == 0)
{
zeroCount++;
}
n = n / 2;
}
return zeroCount;
}
Your approach is good, but I think there's a better way to do it. The Integer class has a static method that returns the binary of a number: Integer.toBinaryString(num) . This will return a String.
Then, you can just check if there are any 0 in that string with method that has a for loop and evaluating with an if:
public int getZeros(String binaryString){
int zeros = 0;
for(int i=0; i < binaryString.length; i++)
if(binaryString.charAt[i].equals('0')
zeros++;
return zeros;
}
I believe this would be a simpler option and it doesn't have any errors.
Once m == 0.0, it will never change, so your while loop will never stop.
If you start with a number m >= 0, it can never become negative no matter how many times you divide it by 2 or use Math.floor. The loop should stop when m reaches 0, so change the condition to while (m > 0.0).
Note that you could do the same thing with built-in standard library methods. For example, there is a method that returns the number of leading zeros in a number, and a method that returns the number of bits set to 1. Using both you can compute the number of zeros that are not leading zeros:
static int binaryZeros(int n) {
return Integer.SIZE - Integer.numberOfLeadingZeros(n) - Integer.bitCount(n);
}
Here is one way. It simply complements the integer reversing 1's and 0's and then counts the 1 bits. You should not be using floating point math when doing this.
~ complements the bits
&1 masks the low order bit. Is either 1 or 0
>>> shifts right 1 bit including sign bit.
System.out.println(binaryZeros(44) + " (" +Integer.toBinaryString(44) +")");
System.out.println(binaryZeros(-44) + " ("Integer.toBinaryString(-44)+")");
public static int binaryZeros(int v) {
int count = 0;
while (v != 0) {
// count 1 bits
// of ~v
count += (~v)&1;
v >>>=1;
}
return count;
}
Prints
3 (101100)
4 (11111111111111111111111111010100)
Just be simple, whe there's Integer.bitCount(n) method:
public static int binaryZeros(int n) {
long val = n & 0xFFFFFFFFL;
int totalBits = (int)(Math.log(val) / Math.log(2) + 1);
int setBits = Long.bitCount(val);
return totalBits - setBits;
}
public static int getZeros(int num) {
String str= Integer.toBinaryString(num);
int count=0;
for(int i=0; i<str.length(); i++) {
if(str.charAt(i)=='0') count++;
}
return count;
}
The method toBinaryString() returns a string representation of the integer argument as an unsigned integer in base 2. It accepts an argument in Int data-type and returns the corresponding binary string.
Then the for loop counts the number of zeros in the String and returns it.

Prime Number checker is not working

This is the code for a function that is supposed to return true if the input is prime and returns false if it is not.
This is how I intended for it to work: lets say that y = 7, the loop starts with n=1. Since 1(n) is less that 7(y) the loop can iterate. The program checks if y divided by n has a remainder of 0, meaning that n is a factor of y. If it is true, then it checks to see if the factor does not equal 1 or y (7), because if they dont then that means that y has more factors other than its self and 1, meaning that it is not prime, so it should automatically end the function and return false. but since 7 has only two factors, 1 and 7, and they either equal 1 or itself (y) then after the end of the loop, it should return true.
I don't understand why it isn't working.
public static boolean checkIfPrime(long y) {
for ( long n =1L; n <= y; n++) {
if(y%n == 0) {
if( n != 1L || n != y) {
return false;
}
}
}
return true;
}
With a few optimizations the code will be like this
static boolean isPrime(long n){
long lim = (long) Math.sqrt(n);
if(n%2 == 0 && n != 2)
return false;
for (int i = 3; i <= lim; i=i+2)
if(n%i == 0)
return false;
return true;
}
This code:
checks if the number is even and different from 2 (all even numbers
except 2 are compound).
next iterates from 3 to sqrt(n), thats because to prove a number is
prime you don't need to check all the dividers (if you don't believe
me try, and if still don't believe use n/2 wich is enough but not the
minimum value).
For loop pace start from 3 and add 2 in each iteration getting only odd numbers as divder (we first checked that it wasn't an even number).
Remove equal to operator in n <= y. Start your loop from 2. It must be like this. ( long n =2; n < y; n++)
For what you are trying to achieve, pseudo code in my opinion should look like this:
set a flag = true;
Loop from 2 to y-1{
if(y%n==0){
flag = false
break; // Very important
}
}
check flag condition & return (if some othe computation is required) or just return flag
if( n != 1L || n != y) : is adding a check condition unnecessarily to every iteration. try to avoid it.
Why use a flag instead of direct return statement ? Just a preference, a direct return definitely would work in this case.

What does this part in code mean? (Java)

Hey guys im new to java and i came across this thing
Ok so here i got something i just cant comprehend
here i have this class:
class FailSoftArray {
private int a[]; // reference to array
private int errval;
public int length;
public FailSoftArray(int size, int errv) {
a = new int[size];
errval = errv;
length = size;
}
public int get(int index) {
if(indexOK(index)) return a[index];
return errval;
}
public boolean put(int index, int val) {
if(indexOK(index)) {
a[index] = val;
return true;
}
return false;
}
private boolean indexOK(int index) {
if(index >= 0 & index < length) return true;
return false;
}
}
What does indexOK(index) mean? What does it do?
This is a method to determine if the index its going to get in the array is valid.
Normally, if a value less than zero or greater than or equal to the length of the array was used as an index, it would cause an error, throwing an IndexOutOfBoundsException, since an array is indexed from 0 to length - 1.
The method avoids that possible outcome by ensuring the index will always be valid before using it, and it does this by comparing the index to see if it's >= 0, then comparing < length, then the & makes sure both are true (if both conditions are true, it can be used as an index to the array without throwing an exception.)
When you call indexOK, your program runs the following method, with an index as an argument:
private boolean indexOK(int index) {
if(index >= 0 & index < length) return true;
return false;
}
}
indexOK returns a boolean value, so the result is either true or false. When is the result true?
if(index >= 0 & index < length) return true;
return false;
If the argument is larger than or equal to zero AND the argument is less than length, the result is true. Otherwise, the result is false.
The purpose of indexOK is to check whether or not a value is an appropriate index for an array. A negative index is invalid, as is an index which equals or exceeds the length of the array it references. So the check
index >= 0
determines whether or not the index is negative, and the check
index < length
determines whether or not the index equals or exceeds the length of the array it references.
Let me rewrite the method in a way that is more understandable:
private boolean indexOK(int index) {
if(index >= 0 & index < length) {
return true;
}
return false;
}
The method will return true, when the value of index is atleast 0 and smaller than length at the same time. You can use an if-statement without its curly brackets, but it will only use the following line as the 'inner block'. This is a rather bad practice, since it's a little unclear. Furthermore, it can be easily the cause of unwanted bugs and errors, since adding lines to the 'inner block' without adding curly brackets around them isn't that uncommon. In my humble opinion, 1 line (or 2 brackets) more of code isn't that much and one should always add them.

How do I use a recursive algorithm to determine whether the array contains two elements that sum to a given integer?

Okay guys thanks for all the help! Special thanks to #pjs for giving me an idea of how to do it. Here is my new code, but for some reason it won't reach one of the base cases. Sorry if I deleted the old code, this is the first time I posted here and I am not sure if I should answer my own question with the new code.
//initialized int start = 0
//initialized int end = length of the array
//here goes the constructor
public boolean kPairSum(Integer k) {
if (sortedIntegerArray.length < 2) { //if array is less than two return false
return false;
}
else if (start == end) { //once the start and the end meets. This is the base case that doesn't seem to work for me.
return false;
}
else {
int currentStart = sortedIntegerArray[start]; //get first int in the array
int currentEnd = sortedIntegerArray[end-1]; //get the very last int in the array
int sum = currentStart + currentEnd; //get the sum
if (k.equals(sum)) { //compare sum and k if equal
return true;
}
else if (sum <k) { //if sum is less than k then increment value of start
start++;
return kPairSum(k);
}
else if (sum > k) { //if sum is greater than k then it decrements value of end
end--;
return kPairSum(k);
}
else { //not sure if this is right, should I just get rid of the else if statement for sum > k and change it to just an else? I wrote this down cause it has to return a type of boolean.
return kPairSum(k);
}
}
Your array is called sortedIntegerArray, but you don't seem to be leveraging that fact.
Start by summing the two ends of the array. If the sum is smaller than k, one of the two elements of the sum has to be larger. You can only get a larger value by incrementing the lower index because the elements are ordered. Similarly, if the sum is larger than k, one of the two elements has to be smaller, so you need to decrement the upper index. In either case, the structure of the problem is the same but you're now operating on a subset of the array specified by which of the indices you incremented/decremented. Base cases are that you found two values which sum to k, or that the indices have met somewhere. The recursion should leap out at you. Since each recursive call either increments or decrements a boundary index until they meet in the middle, it's O(n).
Your recursive call is never invokes:
if (sum == k) { //compare to given k
return true;
} else if (xx == sortedIntegerArray.length-1 || sum != k) {
return false;
}
Note that you basically have two choices: sum==k, and then - return true, or sum!=k - and then return false. The recursive invokation is not reachable.
An O(n) (average case) solution can be achieved using a hash table. The idea is to add each element to the hash table while iterating, and check if there is an existing element that completes to k.
for each element e in arr:
if e is in table:
return true
table.add(k-e)
return false //no pair was found that sums to k
A recursive solution that checks all pairs, is basically brute force that is similar to a nested for loop.
//i is the index we are now checking, b is a boolean indicating we have already reduced one element
kSum(k,i,b):
if i == arr.length
return false
if b == true && k == 0:
return true
if b == false:
return kSum(k-arr[i],i+1,true) || kSum(k,i+1,false)
else:
return kSum(k,i+1,b)
I have two implementations here:
One I initially got to work and with Amit answer, I improved it further. It also prints/return the indices that make up the sum. works with both sorted and unsorted array in O(n). ofcourse, this is not recursive.
public static void sumArray2(int[] arr, int sum){
Map <Integer, Integer> map = new HashMap<>();
for (int i=0; i < arr.length;i++){
map.put(arr[i], i);
}
for (int i =0; i < arr.length;i++){
int diff = sum-arr[i];
if (map.containsKey(diff) && i!=map.get(diff)) {
System.out.printf("The two indices are %s and %s%n ",i,map.get(diff));
return ;
}
}
System.out.printf("The sum:%s cannot be formed with given array:%s",sum,Arrays.toString(arr));
return ;
}
//returns a boolean if sum could be formed.
public static boolean sumArray3(int[] arr, int sum){
Map <Integer, Integer> map = new HashMap<>();
for (int i =0; i < arr.length;i++){
int diff = sum-arr[i];
if (map.containsKey(arr[i])) {
System.out.printf("The two indices are %s and %s%n ",i,map.get(arr[i]));
return true;
}
map.put(diff,i);
}
System.out.printf("The sum:%s cannot be formed with given array:%s",sum,Arrays.toString(arr));
return false;
}
don't know how to add formatted comment, so here is enhanced version, than Amit provided, works with O(n) :)
def check(source, need):
target = [need-i for i in source]
target.reverse()
i = 0
j = 0
# walk thru lists same "merge" to find a match
for i in xrange(0, len(source)):
while j < len(target) and source[i] > target[j]:
j=j+1
if i != len(source)-j-1 and j < len(target) and source[i] == target[j]:
return True
return False

Selection sorting with an array

I need help sorting an integer array using selection sort. It won't sort for some reaons. Below is my demo/main.
02
20
01
it should be
01
02
20
My demo/main:
public static void main(String[] args) {
SelectionSortArray[] ints = new SelectionSortArray[3];
ints [0] = new SelectionSortArray(02);
ints [1] = new SelectionSortArray(20);
ints [2] = new SelectionSortArray(01);
System.out.println("Unsorted array: ");
for (int index = 0; index < ints.length; index++) {
System.out.println(ints[index]);
}
SelectionSort.selectionSort(ints);
System.out.println(" ");
System.out.println("Sorted array using selection sort: ");
for (int index = 0; index < ints.length; index++) {
System.out.println(ints[index]);
}
}
Your compareTo method in the SelectionSortArray class is incorrect. The compareTo method must return an int less than zero if the current object is less than the other object, yet you have it returning 1.
Quoting from the linked Javadocs:
Compares this object with the specified object for order. Returns a
negative integer, zero, or a positive integer as this object is less
than, equal to, or greater than the specified object.
Try these changes:
if (num == other.num) {
result = 0; // This was correct; no change here.
} else if (num < other.num) {
result = -1; // Changed from 1 to -1.
} else {
result = 1; // 1 or 2 is fine, as long as it's positive
}
Your CompareTo function is wrong. Just change it to:
public int compareTo(SelectionSortArray other) {
return num.compareTo(other.num);
}
The key is the -1 / 0 / 1 return codes, rather than the "0,1,2" that you're using.
Generally if you're comparing built in types, it's easier to just delegate to the built in comparison operators.
Note: To use "num.compareTo" you need to use "Integer" rather than "int". If you want to stick with "int", you need the solution posted by rgettman.
Note that along with the changes to compareTo,
return Integer.compare(this.num,other.num)
Which is implemented to return what you are returning but in a concise way
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
if you want to see the printed output in the way you listed in your question use
System.out.format("%02d%n",ints[index].num);
or alter toString() to return String.format("%02d",num)
You might also want to see java.util.Arrays source code so see how few other similar methods have been implemented. Also consider changing your class name to indicate that it holds number CustomNumber and encapsulate your class to avoid direct access to num.
And another Interesting catch in your code
SelectionSortArray[] ints = new SelectionSortArray[8];
ints[0] = new SelectionSortArray(01);
ints[1] = new SelectionSortArray(02);
ints[3] = new SelectionSortArray(03);
ints[4] = new SelectionSortArray(04);
ints[5] = new SelectionSortArray(05);
ints[6] = new SelectionSortArray(06);
ints[7] = new SelectionSortArray(07);
ints[8] = new SelectionSortArray(08);//???
if you precede a number with 0 it will be an Octal number and allowed digits are 0 - 7 hence you will see compilation error above. Also
System.out.println(0123);
System.out.println(0234);
will not print
0123
0234
as you (un)expected !
83
156
Just be cautious while using octal numbers in your code.

Categories

Resources