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);
}
}
Related
public class TestPossibleNumbers {
public static void main(String[] args) {
int input[] = { 1, 2, 3 };
// int input[] = {10,11,12,13};
possibleNumbers(input, 0);
}
public static void possibleNumbers(int[] x, int index) {
if (index == x.length) {
for (int i = 0; i < x.length; i++) {
System.out.print(x[i] + " ");
}
System.out.println();
}
for (int i = index; i < x.length; i++) {
int temp = x[index];
x[index] = x[i];
x[i] = temp;
possibleNumbers(x, index + 1);
temp = x[index];
x[index] = x[i];
x[i] = temp;
}
}}
Can anyone help me to understand the code inside for loop?
This program run perfectly. But, I am unable to figure out how it is working
You are recursively calling the method again at:
possibleNumbers(x, index + 1);
Thus the method runs the method again, with index + 1 passed. It checks if
if(index == x.length)
If the statement is correct it prints the numbers.
It then enters the 2nd for loop again(if the if statement was incorrect it will still enter it). And calls the recurring method again. It will keep entering 2nd for loop but when "index" will be equal to or greater than "i.length" no iterations of the for loop will run because you specified for loop to run only when:
i<i.length
When 2 for loop does not do any iterations the method will stop recurring. So in your case when index is equal to 3 no iterations of 2nd for loop will run.
Try running debug step by step to see what is happening more in depth.
The Program prints permutation of numbers not combination.
Permutation - Order matters
Combination - Order doesnt matter and more of choosing k elements out of n
for example
int a= {a,b};
permutation = {ab,ba}
whereas combination ={{},{a},{b},{a,b}}
To understand how the program works
go through the following link will
https://www.geeksforgeeks.org/write-a-c-program-to-print-all-permutations-of-a-given-string/
Don't get confused on recursion inside for loop.
if (index == x.length) is the terminating condition for recursion.
Inside the for loop before and after calling the recursive call possibleNumberselements are swapped.
Before swap helps to generate all possible outcomes and after swap elements will swap to previous position so that all other permutation will be generated from the for loop. It may sounds confusing please go through the link.
I'll provide an alternative explanation that I feel is more intuitive.
Consider the case of only 1 number in the list: [a]. This is pretty trivial: there's a single combination [a].
Now consider the case of 2 numbers in the list: [a, b]. In this case you can take each of the elements in turn and then look at all combinations of the remaining element using the previous method and then add the element back.
Now consider the case of 3 numbers in the list: [a, b, c]. In this case you can take each of the elements in turn and then look at all combinations of the other 2 elements using the previous method and then add the element back.
And so on for 3, 4, 5... elements.
So, in general, consider the case of n numbers in the list: [a1, a2, ... an]. In this case take each of the elements in turn and then look at all combinations of the other n-1 elements using the exact same method and then add the element back.
Converting to pseudo code:
getCombos(values)
for each value
for each combo in getCombos(values with value removed)
add value + combo to results
return results
The only thing to add is the base case which is necessary for all recursive implementations. One possibility is the case of a single item. However there's an even simpler one: if there are no values then the result is a single empty list.
So converting that to Java, using sets to make clear that the elements need to be unique (to avoid duplicate results), using streams and making it generic so it'll work for any type:
Stream<List<C>> combos(Set<C> values) {
if (values.isEmpty())
return Stream.of(new ArrayList<>());
else
return values.stream().flatMap(value ->
combos(values.stream()
.filter(v -> !v.equals(value))
.collect(toSet())).peek(r -> r.add(value)));
}
Your code is really just an alternate implementation of the same algorithm that swaps the element under consideration to the front of the array instead of creating a new collection.
I have a question that doesn't seem possible to me. I have 2+ arrays which I have to compare for common values. I am supposed to do this in O(N) comparisons but can't think of a way. Specifically (k-1)N comparisons where k is the number of arrays. I've narrowed down how I can take multiple arrays and just merge them into a single array. I've gotten that the smallest array is the limiting factor so if I sort that I can save the most comparisons. After spending half the day staring at my screen I've even come up with a way to do this linearly if I discount any duplicates, but I have to keep duplicates So, as far as I know in order to compare any arrays you need at least 2 for loops which would be O(N^2) wouldn't it? I'm also not allowed to hash anything.
For example if I had {1,3,4,3,4,5} as a master and {1,1,3,5,9,3,7} and {3,5,8,4,0,3,2} as arrays to be compared I'd need to have a final of {3,3,5} since I can't get rid of any dupiclates.
I don't want anyone to write the code, I just need to know what I should be doing in the first place.
Use an array of ints. Taking your first list, for each element, set the value at that index to 1. So if the first element is 3, put 1 in array[3]. Now, we know that 3 is present in first list. Putting 1 will help you distinguish from a 3 that is present in the earlier list versus a 3 which is repeated in current list.
Iterate through all the other k-1 lists
For every element, check the value in array for that index
If the value is 0, set it to this list number
If the value is a number less than this list number, this number is a duplicate and has already appeared in a previous list.
If this number is equal to this list index it means this number already occurred in this list but not in previous lists, so not yet a duplicate.
The numbers that you are getting as duplicates, add them to another list.
Finish all iterations
Finally print the duplicates.
Original Wrong Answer
Create a HashSet<int>
Take all values from master and add to it - O(master list count)
Now just iterate through first and second arrays and see if their elements are in that HashSet - O(each list count)
If the lists are sorted, then it's relatively straightforward if you do something like this:
List<Integer> intersection = new ArrayList<>();
int i = 0;
int j = 0;
while (i < list1.size() && j < list2.size()) {
int a = list1.get(i);
int b = list2.get(j);
if (a < b) {
i++;
} else if (b < a) {
j++;
} else { // a == b
intersection.add(a);
i++;
j++;
}
}
On each iteration of the loop, the quantity i + j increases by at least 1, and the loop is guaranteed to be done when i + j >= list1.size() + list2.size(), so the whole thing does at most O(list1.size() + list2.size()) comparisons.
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")
(I'm new at Java, coming over from Python ---)
I'm going through a tutorial and they've created a program which counts how many times a number appears in a file, then returns that number. One particular part of the program is somewhat mysterious to me and deals with the ArrayList's .get and .set (methods? functions?). The program goes like this:
// (Scan a file with the numbers, say, 2 2 3 4, and put it into data1 variable.)
// (Make An Empty ArrayList with a bunch of 0's)
Scanner data1 = null;
ArrayList<Integer> count = new ArrayList<Integer>();
Integer idx;
while(data1.hasNextInt()){
idx = data1.nextInt();
System.out.println(idx);
System.out.println(count.get(idx)+1);
count.set(idx,count.get(idx)+1);
}
//Then prints out all the values; the ArrayList contains the number of times the number n occurs in the n-th index.
My question comes at the "while" part. For concrete, let's assume data1 has the numbers 2 2 3 4. It seems that it takes idx = 2, then puts a 1 in count[2], which is reasonable. It then takes idx = 2 again (the next integer in data1) and puts a 2 in count[2], which is also reasonable. At this point, the next number in data1 makes idx = 3, but it occurs at the index 2 in the ArrayList, so it should put a 3 in count[3], which is incorrect.
So, what is .get and .set doing here? Do they pop the elements off of the list when they're done with it? Am I overlooking something?
A .get() will not automagically get elements from a List which does not have that many elements. Note: list indices, like arrays, start at 0.
If you do:
final List<Integer> = new ArrayList<Integer>();
list.get(0);
this is a runtime error (IndexOutOfBoundsException) because your list has no elements.
You have to fill it:
list.add(1); // append an element
list.get(0); // returns element at index 0
list.get(1); // IndexOutOfBoundsException!
The .set() method takes an index and a value at an argument. In a similar vein, you cannot set an element which does not already exist, except at the very end of the list:
// start from an empty list
list.set(1, 32); // IndexOutOfBoundsException!
list.set(0, 32); // OK
Final note: try not to use list[i], bracket indices are used for arrays ;) Note that arrays are not resizabe in Java. Lists (which are an implementation of a Collection), however, are. But you must append to them.
So, what this line does:
count.set(idx, count.get(idx) + 1);
is take the value at index idx, add 1 to it, and sets back this value at the same index.
In your specific case, what you are looking for is a sparse array. In Java we use a HashMap<Integer, Integer> for that purpose. You don't need any initialization with zeros, but you do need to check for null:
final Integer curr = count.get(idx);
count.put(idx, curr == null? 1 : curr+1);
You are currently using an ArrayList, which acts like an array, but makes it easier to expand it - for example, add elements to it.
What you want is the java equivalent of the python dict, a key/value storage, in java, this is called a HashMap<K,V> (docs).
Scanner data1 = null;
HashMap<Integer, Integer> count = new HashMap<Integer, Integer>();
Integer idx;
while(data1.hasNextInt()) {
idx = data1.nextInt();
System.out.println(idx);
Integer g = count.get(idx)+1;
if(g == null) {
g = 0;
}
g++;
System.out.println(g);
count.put(idx, g);
}
Does anyone know how I would work out if all elements in an array but one have the same value?
I have been trying to work it out for ages but cannot solve it. For example testing an array that has 5 elements to see if it has 4 identical values.
Thanks
Use a map.
Map<X, Integer> map = new HashMap<X, Integer>(); // where X is the array type
Integer ct;
for(X item : array){
ct = map.get(item);
if(ct == 0) ct = Integer.valueOf(1);
else ct = Integer.valueOf(ct.intValue()+1);
map.put(item, ct);
}
// now test if map.values() consists of Integer.valueOf(1) and (optionally)
// another positive integer (thx aioobe)
Step by Step:
Get the first element.
Loop all the array elements and count the number of times they don't
match that first element.
If all of the elements match, you have your answer (all are equal).
If only one of the elements do not match, you have your answer (one
is different).
If some of the elements do not match, you have your answer (more than
one is different).
In none of the elements match, get the second element and repeat the
test.
If only one of the elements do not match, again only one is different (the first one).
Else, the number of different elements is bigger than one.
The approach I would choose is:
iterate over all elements and put them in a Map (HashMap in Java).
the key is the element, and the value is the counter of the appearance.
example: your array: A A A A B
map:
A -> 4
B -> 1
After you have constructed that map it's easy to find out if your array matches that criteria.
The map must have exactly 2 elements (map.size()).
Exactly one of the elements has the counter 1.
If you assume that adding to a map happens in constant time you'll have an overall complexity of 2n (iterate over array and iterate over map).
I came up with this trick :-)
public static boolean allButOneSame(int[] arr) {
if (arr.length <= 1)
return arr.length == 1;
Arrays.sort(arr);
return arr[0] != arr[arr.length-1] &&
(arr[0] == arr[arr.length-2] ||
arr[1] == arr[arr.length-1]);
}
(Relies on comparable values such as integers though!)
Iterate array, by comparing 1st element and x+1 elements where x is 2,3,4,...array.length()
If comparison fails then increment a counter
if ((counter==0) || ((counter> 1) && (counter != array.length-1))) then condition is not met
counter=0 means, all are same elements
counter=array.length-1 means sorted order eg: 4,5,5,5,5,5,5
Complexity ->time: O(n), no extra space other than counter
Here's another approach:
public static <Item> boolean allButOneSame(List<Item> items) {
// Make sure we have 2 different elements (or 1 element in total)
if (new HashSet<Item>(items).size() != 2)
return items.size() == 1;
// Create a temporary copy
List<Item> tmp = new ArrayList<Item>(items);
// Remove all elements equal to the first one.
tmp.removeAll(Collections.singleton(items.get(0)));
// Check the number of remaining elements.
return tmp.size() == 1 || tmp.size() == items.size() - 1;
}
It takes a List as input. Use Arrays.asList if start with an array.
You could also add all array elements into a LinkedHashSet (no duplicates, insertion order is preserved) and look at the set's .size()