I'm looking for some advice on a Java assignment. What I'm asked to do is perform different operations on numbers that are stored in a linked list, with each digit in a separate node. The point is to write a program that can do arithmetic on numbers that are very very large.
The particular problem that I'm looking for help on is for writing a method that compares two numbers, similar to regular compareTo() method for ints. It should return -1 if this.num < num, +1 if this.num > num, and 0 if they are equal.
What's making this difficult for me is the fact that the assignment specifies that the linked lists should store the numbers in reverse order. For example, the linked list for the number 145 would look like:
5 => 4 => 1 => null
This makes it easier to add numbers together but it's making it a headache for me when trying to compare. Here's what I've come up with, the comments explain how it's supposed to work.
public int compareTo(LLNum list)
{ // Compares two numbers.
// If the two numbers are of a different length, clearly the shortest is the smallest.
// If the two numbers are of equal length, call traverseToCompare to do the comparison.
if (this.len > list.len)
{
compareResult = 1;
}
else if (this.len < list.len)
{
compareResult = -1;
}
else if (this.len == list.len)
{
traverseToCompare(this.head, list.head);
}
return compareResult;
}
public void traverseToCompare(ListNode node1, ListNode node2)
{ // In the case that both numbers are of the same length, recursively traverse the list.
// compare each digit individually while unwinding the stack.
// Once two digits are found to be different, break out of the unwinding (Note: I could not find a way of breaking out)
// Since the dominant digit is at the tail end, this ensures the least number of comparisons.
if (node1 == null || node2 == null)
{ // Base case. Handles the case where both numbers are identical.
compareResult = 0;
return;
}
traverseToCompare(node1.getNext(), node2.getNext());
if (node1.getItem() > node2.getItem())
{
compareResult = 1;
}
if (node1.getItem() < node2.getItem())
{
compareResult = -1;
}
return;
}
The numbers being in reverse order is what pulled me towards recursion. I thought I would recursively traverse the list and then compare each digit on the way out, and somehow break out of the recursion at the first digits that are not the same. I realize this is not a usual way to use recursion but I wasn't sure how else to do it. Is there a way I could break without just throwing an exception? I think that might be a little too sloppy. Or any suggestions on how to do this without recursion?
Please don't just give me some code to copy and paste. I'm just looking to be pointed in the right direction. Thanks!
If I had to do this I would first check the lengths of both lists (like you did). If they're equal, a better way to do the comparison would be to create an iterator for each list. You can then increment the iterators at the same time and compare the values at that position in the linked lists. Doing it this way, you can simply stop comparing the lists once you have determined that one contains a larger number than the other.
In traverseToCompare you will need to take care of some cases.
It will be better and clean if you do not use the recursion.
Following can be a solution
boolean areSame = true;
boolean digitDiffer = false;
int compareResult = 0;
int length = node1.length
for(int i=0; i<length; i++)
{
if(!digitDiffer && ((node1.getItem() == node2.getItem()))
{
continue
}
else
{
digitDiffer = true;
if(node1.getItem() >= node2.getItem())
{
compareResult = 1
}
else
{
compareResult = -1;
}
}
}
return compareResult;
The best way to do it is to traverse the list for each number and construct the number and then compare the 2 numbers.
The way to construct a number from the list would be
int i = 0
int f = 1
Do while GetNext() <> Null
i = i + GetCurrentItem() * f
f = f * 10
End Do
For eg. if the number is 145, then the list would have 5->4->1
So running the above code
i = 0
f = 1
i = i + 5*1 = 5
f = f * 10 = 10
i = i + 4*10 = 45
f = f * 10 = 100
i = i + 1*100 = 145
f = f * 10 = 1000
So it comes out with i = 145.
It would have been much easier to do using plain String; as you could store data of any length. But anyway the requirement is for LinkedList :
Now as the data is stored in revers order; this means you can't decide response of compareTo method until you go through the complete list, as most significant data is stored at last position.
5 --> 4 --> 1 == 145
1 --> 4 --> 5 == 541
So read through the whole least; then you can store the value in a String and then decide compareTo method result.
traverseToCompare method is called for same length items. So you can write your own algorithm to compare two numbers stored in String.
Edit
If String is not allowed
Then will suggest you to do the same thing manually; iterate through the whole list compare the last node, if last node is same then compare the previous node and so on...
Related
I have just started my long path to becoming a better coder on CodeChef. People begin with the problems marked 'Easy' and I have done the same.
The Problem
The problem statement defines the following -:
n, where 1 <= n <= 10^9. This is the integer which Johnny is keeping secret.
k, where 1 <= k <= 10^5. For each test case or instance of the game, Johnny provides exactly k hints to Alice.
A hint is of the form op num Yes/No, where -
op is an operator from <, >, =.
num is an integer, again satisfying 1 <= num <= 10^9.
Yes or No are answers to the question: Does the relation n op num hold?
If the answer to the question is correct, Johnny has uttered a truth. Otherwise, he is lying.
Each hint is fed to the program and the program determines whether it is the truth or possibly a lie. My job is to find the minimum possible number of lies.
Now CodeChef's Editorial answer uses the concept of segment trees, which I cannot wrap my head around at all. I was wondering if there is an alternative data structure or method to solve this question, maybe a simpler one, considering it is in the 'Easy' category.
This is what I tried -:
class Solution //Represents a test case.
{
HashSet<SolutionObj> set = new HashSet<SolutionObj>(); //To prevent duplicates.
BigInteger max = new BigInteger("100000000"); //Max range.
BigInteger min = new BigInteger("1"); //Min range.
int lies = 0; //Lies counter.
void addHint(String s)
{
String[] vals = s.split(" ");
set.add(new SolutionObj(vals[0], vals[1], vals[2]));
}
void testHints()
{
for(SolutionObj obj : set)
{
//Given number is not in range. Lie.
if(obj.bg.compareTo(min) == -1 || obj.bg.compareTo(max) == 1)
{
lies++;
continue;
}
if(obj.yesno)
{
if(obj.operator.equals("<"))
{
max = new BigInteger(obj.bg.toString()); //Change max value
}
else if(obj.operator.equals(">"))
{
min = new BigInteger(obj.bg.toString()); //Change min value
}
}
else
{
//Still to think of this portion.
}
}
}
}
class SolutionObj //Represents a single hint.
{
String operator;
BigInteger bg;
boolean yesno;
SolutionObj(String op, String integer, String yesno)
{
operator = op;
bg = new BigInteger(integer);
if(yesno.toLowerCase().equals("yes"))
this.yesno = true;
else
this.yesno = false;
}
#Override
public boolean equals(Object o)
{
if(o instanceof SolutionObj)
{
SolutionObj s = (SolutionObj) o; //Make the cast
if(this.yesno == s.yesno && this.bg.equals(s.bg)
&& this.operator.equals(s.operator))
return true;
}
return false;
}
#Override
public int hashCode()
{
return this.bg.intValue();
}
}
Obviously this partial solution is incorrect, save for the range check that I have done before entering the if(obj.yesno) portion. I was thinking of updating the range according to the hints provided, but that approach has not borne fruit. How should I be approaching this problem, apart from using segment trees?
Consider the following approach, which may be easier to understand. Picture the 1d axis of integers, and place on it the k hints. Every hint can be regarded as '(' or ')' or '=' (greater than, less than or equal, respectively).
Example:
-----(---)-------(--=-----)-----------)
Now, the true value is somewhere on one of the 40 values of this axis, but actually only 8 segments are interesting to check, since anywhere inside a segment the number of true/false hints remains the same.
That means you can scan the hints according to their ordering on the axis, and maintain a counter of the true hints at that point.
In the example above it goes like this:
segment counter
-----------------------
-----( 3
--- 4
)-------( 3
-- 4
= 5 <---maximum
----- 4
)----------- 3
) 2
This algorithm only requires to sort the k hints and then scan them. It's near linear in k (O(k*log k), with no dependance on n), therefore it should have a reasonable running time.
Notes:
1) In practice the hints may have non-distinct positions, so you'll have to handle all hints of the same type on the same position together.
2) If you need to return the minimum set of lies, then you should maintain a set rather than a counter. That shouldn't have an effect on the time complexity if you use a hash set.
Calculate the number of lies if the target number = 1 (store this in a variable lies).
Let target = 1.
Sort and group the statements by their respective values.
Iterate through the statements.
Update target to the current statement group's value. Update lies according to how many of those statements would become either true or false.
Then update target to that value + 1 (Why do this? Consider when you have > 5 and < 7 - 6 may be the best value) and update lies appropriately (skip this step if the next statement group's value is this value).
Return the minimum value for lies.
Running time:
O(k) for the initial calculation.
O(k log k) for the sort.
O(k) for the iteration.
O(k log k) total.
My idea for this problem is similar to how Eyal Schneider view it. Denoting '>' as greater, '<' as less than and '=' as equals, we can sort all the 'hints' by their num and scan through all the interesting points one by one.
For each point, we keep in all the number of '<' and '=' from 0 to that point (in one array called int[]lessAndEqual), number of '>' and '=' from that point onward (in one array called int[]greaterAndEqual). We can easily see that the number of lies in a particular point i is equal to
lessAndEqual[i] + greaterAndEqual[i + 1]
We can easily fill the lessAndEqual and greaterAndEqual arrays by two scan in O(n) and sort all the hints in O(nlogn), which result the time complexity is O(nlogn)
Note: special treatment should be taken for the case when the num in hint is equals. Also notice that the range for num is 10^9, which require us to have some forms of point compression to fit the array into the memory
public static boolean hasTwoPair(int[] arrayOfInts){
}
The method is supposed to return true if it can find two different pairs of matching int values. So if the array was {2,2,4,7,7}, it should return true because it has two 2s and two 7s.
It only applies to different pair values though. If it was {2,2,2,2,5}, it would return false because they are not different pair values.
EDIT: This is what I have so far for the body of the method:
boolean pairFound = false;
int pairValue;
for(int s = 0; s < arrayOfInts.length - 1; s++){
pairValue = arrayOfInts[s];
for(int c = s + 1; c < arrayOfInts.length; c++){
if(pairValue == arrayOfInts[c])
pairFound = true;
}
}
return false; //placeholder
I'm not sure where to go from here.
Since you haven't actually tried any code, I'll give a description of how to solve this problem, but no actual code.
Start with a boolean like pairFound that's initialized to false and change to true when you find your first pair. Additionally, you'll need an int (pairValue to keep track of the value of the first pair found (if you found one).
Iterate through, looking for a pair. If you find a pair, and pairFound is false, set pairFound to true, and set pairValue to the value of your first found pair. Now keep iterating through.
If you find a pair and pairFound is true and the pair is != pairValue, then return true;. If you iterate through everything and haven't returned true yet, then you can return false.
Based on your updated question, you're pretty close.
boolean pairFound = false;
int pairValue = Integer.MIN_VALUE;
//or some value that arrayOfInts will never have based on context
for(int s = 0; s < arrayOfInts.length - 1; s++){
if(arrayOfInts[s] == pairValue) {
continue;
}
for(int c = s + 1; c < arrayOfInts.length; c++){
if(arrayOfInts[s] == arrayOfInts[c]) {
if(arrayOfInts[s] != pairValue) {
if(pairFound) {
return true;
}
pairValue = arrayOfInts[s];
pairFound = true;
break;
}
}
}
}
return false;
This task asks you to build a list of counts:
Create a data structure (say, a Map<Integer,Integer>) containing a count for each number from the array.
Go through the map, and count the number of entries with the count of two and above.
If you counted two or more items, return true; otherwise, return false.
The counts for your first example would look like this:
V #
- -
2 - 2
4 - 1
7 - 2
You have two items (2 and 7) with counts of 2, so return true.
The counts for your second example look like this:
V #
- -
2 - 4
5 - 1
There is only one item with the count above 2, so return false.
If you use a HashMap, this algorithm produces an answer in O(n).
Sort the array. Then look for the first two consecutive values that match. If found, skip to the first entry that is different from the matched pair and repeat. If you reach the end of the array before either the first or second search succeeds, return false.
You don't need to sort the array, that would give O(n*log(n)) complexity. But your current solution is even worse since it's yielding O(n^2) complexity. But you also don't need a HashMap. A Set and an integer is enough:
For each array element do
Check: is the element already in the set?
If not put it into the set
If yes check if it's equal to your last found Int pair (yes, use a boxed Int, not a primitive int here, to be able to initialize it with null)
If it's equal continue
If it's not equal
If the last found pair is null set it to elements value
Otherwise you're done and you have at least 2 different pairs
If you iterated over the list without reaching the last condition you don't have 2 different pairs
As for the Set implementation I would recommend a HashSet
There is more to say here though. If you implement it like this you make no assumption about integers and indexable arrays. All you need is a list of comparable elements. So you could make the signature of your method much more generic:
public static boolean hasTwoPair(Iterable<E> iterable)
But since arrays don't support generics and the Iterable interface every client of this method would have to transform Array parameters to an Iterable with the asList() method. If that's too inconvenient you can provide another method:
public static <T> boolean hasTwoPair(T[] array)
In general it's a good idea to use the most generic type possible when you design API's (also see Item 40 and 52 in "Effective Java, Second Edition")
How can I write a function that takes an array of integers and returns true if there exists a pair of numbers whose product is even?
What are the properties of even integers? And of course, how do you write this function in Java? Also, maybe a short explanation of how you went about formulating an algorithm for the actual implementation. This is from the book however I am only trying to learn the explanation.
A pair of integers will always produce an even product if at least 1 of them is even. It can't produce an even product if both are odd. Therefore, you just need to check if there is at least 1 even number in the array.
This is a mathematical concept and known fact that, any even number multiplied by any other number is an even number. And so, all you have to do is return true if any one number in the array is an even number.
As others have pointed out, just having one even number is enough.
You only have to iterate until you find an even number, or the end of the array in which case there is no even number in it.
public static boolean hasEvenNumber(int[] vals) {
int i = 0;
while(i < vals.length) {
if(vals[i] % 2 == 0) {
return true;
}
i++;
}
return false;
}
Algorithm is quite simple .
You need a single even number should present in the array of integers .
Because multiple of even number with odd/even number results in a even number . So you can return true if there is an even number .
In java ,
public static int has_even_pair(int [ ] values,int n) //method definition to find sum
{
int i;
for(i=0; i< n; i++)
{
if (values[i] % 2 == 0 )
{
return 1;
}
}
return 0 ;
}
I have sets of three numbers, and I'd like to compare numbers in a set to another set. Namely, that each number in the first set is less than at least one number in the other set. The caveat is that the next numbers in the first set must be less than a different number in the second set (i.e., {6,1,6} would work against {8,8,2}, but {6,2,6} against {8,8,2} wouldn't). I have a working method, but it's brute force and ugly.
If we have setA and setB, and each of those have elements a, b, and c:
if(setB.a < setA.a)
if(setB.b < setA.b)
if(setB.c < setA.c)
return true;
else if(setB.b < setA.c)
if(setB.c < setA.b
return true;
and so on...
EDIT: I just realized you said these sets are hardcoded at 3 values. This is a super general algorithm for sets of any size.
For a 3-value set, you can do the same dumping and sorting of set elements, and then do:
if(setB.a < setA.a)
if(setB.b < setA.b)
if(setB.c < setA.c)
return true;
return false;
======================================================
A general algorithm:
This is the most efficient way I can immediately think of to do this.
pseudocode (more pythonic than java, sorry-- hopefully the comments explain):
list l1 = set1.items() //get the items out
list l2 = set2.items()
l1 = sort(l1)
l2 = sort(l2) //sort the lists
int set2idx1 = l1[0].find_closest_greater_than_value(l2) //binary search or something
if set2idx1 exists:
l2 = l2[set2idx1+1:] //in python this means l2 is reassigned to a subarray of l2 starting at set2idx1+1 going to the end of l2
else:
return false
for(int i=1; i<l1.len; i++)
int set2idxi = l1[i].find_closest_greater_than_value(l2) //binary search or something
if set2idxi exists:
l2 = l2[set2idxi+1:]
else
return false
return true
comment if anything doesn't make sense
EDIT EDIT:
explanation of the general algorithm for any interested parties:
dump the set elements into arrays
sort those arrays
iterate through the first array, seeing if there is a value in the 2nd array that is greater than the current value. If so, get the index of that value and lop off everything before and including that index and reassign the 2nd array variable to what remains.
if there ever is no such value (either because it doesn't exist or you've run out of values to test, return false). Otherwise, at the end, return true.
The idea here is that since the arrays are sorted, you know that any element that is greater than the matched element in the 2nd array will be greater than the element you're testing against in the 1st array. So you can just chop off the lower values, and since you don't want to use the same value, you can chop off the one you found, too. If you ever return false you know it's because either there were no greater values, either because the numbers in array1 were all greater than the numbers in array2, or because there weren't enough numbers in array2 greater than the numbers in array1.
What about the following pseudocode?
Condition(A : Set, B : Set) : Bool =
Let a := max(A), b := min(B) In
// Namely, that each number in the first set is less than at least one number in the other set
If a <= b Then
// the next numbers in the first set must be less than a different number in the second set
Condition(without(A, a), without(B, b))
Else
False
EndIf
Where without(A, a) means the set A minus the set {a}
It seems that a List would do better than a Set since your example includes duplicate elements. Simply:
1) Sort the two lists.
2) Trim off the first few elements from the second list until the sizes of the first and second list are equal.
3) Directly compare list1[i] with list2[i] for each i.
Code:
import java.util.*;
class Main {
public static void main (String[] args) {
List<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
list1.add(3); list1.add(7); list1.add(7);
list2.add(8); list2.add(8); list2.add(2); list2.add(1); list2.add(5);
//algorithm:
Collections.sort(list1);
Collections.sort(list2);
List<Integer> list3 = list2.subList(list2.size() - list1.size(), list2.size());
System.out.println(list1.size() + " " + list3.size());
boolean pass = true;
for(int i = 0; pass && i < list1.size(); i++)
if(list1.get(i) >= list3.get(i))
pass = false;
System.out.println(pass);
}
}
I need to find combination of combination in JAVA.
I have for instance 6 students in class. Out of them, I need to create combination of 4 people in group, and for each group I can choose an intimate group of 2.
I have to make sure that there are no doubles (order does not matter).! and need to print the 4 people group.
However, this is the hard part:
So defining students with numbers:
If I print out 1234 as one of the combinations, I can't print out1256 as well, since 12 appears both in 1234 and in 1256.
How can I write it in Java?
EDITED
output of ([1,2,3,4,5],3,2) will be:
Combinations without repetition (n=5, r=3)
{1,2,3} {1,2,4} {1,2,5} {1,3,4} {1,3,5} {1,4,5} {2,3,4} {2,3,5} {2,4,5} {3,4,5}
deleting repeating groups of 2 elements, will leave me only:
{1,2,3} {1,4,5} (i deleted groups that have combinations of 12,13,23,45,14,15 since they already appear in the first two that I have found.
Ok, here's the simple emulation of the process you described. But I use binary numbers to present set, it makes manipulations easier. For example, number 19 is 10011 in binary form: it means students 0, 3 and 4 are selected (there're 1's in those positions).
A little helper first.
// return all subsets of 'set', having size 'subsetSize'
Set<Integer> allSubsets(int set, int subsetSize) {
Set<Integer> result = new HashSet<Integer>();
if (subsetSize == 0) {
result.add(0);
return result;
}
if (set == 0) {
return result;
}
// check if 1st element is present
if (set % 2 == 1) {
// use 1st element, one less element to collect
for (Integer i : allSubsets(set / 2, subsetSize - 1)) {
result.add(i * 2 + 1);
}
}
// not use 1st element
for (Integer i : allSubsets(set / 2, subsetSize)) {
result.add(i * 2);
}
return result;
}
And main program. Suggestions are welcome.
int N = 5;
int M = 3;
int Z = 2;
List<Integer> result = new ArrayList<Integer>();
// get all groups of M elements from 'wholeSet'
int wholeSet = (1 << N) - 1;
for (int s : allSubsets(wholeSet, M)) {
// Check all subsets of 'Z' elements from set 's'
boolean valid = true;
for (int t : allSubsets(s, Z)) {
// check if this Z-element subset already was used
for (int past : result) {
// check if 't' is subset of 'past' set
if ((past|t) == past) {
valid = false;
break;
}
}
if (!valid) {
break;
}
}
if (valid) {
// none of Z-element subsets of 's' were used before
result.add(s);
}
}
But it may require improvements (like memoization) for big inputs. But for now, since you don't say what kind of input you expect, I assume this is good enough.
Imagine you have a Student object with an equals comparing their Primarykey. In your example, student 1 will return 1, 2 will return 2 and so on.
Put them all in the set, this will ensure that there will be no double.
Iterate though the set by 4 then by 2 and will return you your desired result.