Finding a powerset from a linked list - java

I am looking for some help with my Java programming assignment. Using a linked list, I need to print out its power set. For example, the set {1,2,3} should print out
{{},{1}{1,2}{1,3}{1,2,3}{2}{2,3}{3}}. The number of elements in the power set is 2^n.
This needs to be done by calling
HeadNode.PrintPowerSet();
where HeadNode is the first element in the linked list.
I have tried a few things and nothing is working that well. I think the best way to do it would be to call the method recursively until the end sentinel is reached and then work backwards, adding the elements that are left. Sorry I can't post more code or more ideas because nothing I have tried has worked that well. Thanks in advance.
EDIT:
This is the non working code. It returns the set {{1,2,3}{2,3}{3}}
public RSet powerSet()
{
if (this == EMPTY_SET)
return EMPTY_SET;
RSet q = new RSet();
if (q != EMPTY_SET)
q.next = next.powerSet();
q = new RSet(this, n, q.next);
return q;
}
EMPTY_SET is the end sentinel. I've tried writing it out by hand. It helps but I still can't get it. Also this class, RSet, is essentially just a linked list node.

Just iterate all the numbers from 0 to 2^n - 1. Each defines an element of the power set:
The list defines a fixed index on your set. For each number, create a new set. Considering the number in its binary format, add the item in the original set at index i to the set if the bit at index i is 1 and don't add it otherwise.
Then, for each number you will have a set that is an element of the power set.
int n = list.size();
Set<Set<T>> powerSet = new HashSet<Set<T>>();
for( long i = 0; i < (1 << n - 1); i++) {
Set<T> element = new HashSet<T>();
for( int j = 0; j < n; j++ )
if( (i >> j) % 2 == 1 ) element.add(list.get(j));
powerSet.add(element);
}
return powerSet;

Related

Permutation matrix with dynamic variable (days), each day should "generate" one for-loop?

I want to make a permutation matrix using a dynamic variable (days).
My current code has 3 loops (for 3 days), and if I wanted to add another day or delete one day, I would have to add/delete one complete for-loop.
public static ArrayList<ArrayList<Integer>> computePermutations(int stops, int days) {
int maxPerDay = stops - (days - 1);
ArrayList<ArrayList<Integer>> permutationMatrix = new ArrayList<ArrayList<Integer>>();
for (int m = 1; m <= maxPerDay; m++) {
for (int n = 1; n <= maxPerDay; n++) {
for (int o = 1; o <= maxPerDay; o++) {
if (m + n + o == stops) {
ArrayList<Integer> possibleSolution = new ArrayList<Integer>(Arrays.asList(m, n, o));
permutationMatrix.add(possibleSolution);
}
}
}
}
return permutationMatrix;
}
I also need to update the line: ArrayList<Integer> possibleSolution = new ArrayList<Integer>(Arrays.asList(m, n, o));, so the parameters (m, n, o) change depending on the amount of days.
Your question in essence can be summarized as follows
If I have to compute the permutation of n elements, do I need n embedded for cycles?
And the answer is no. It is solvable with embedding n cycles, you are correct in observing that, but it is not necessary, nor advisable. The problem with this kind of solution is that your program will assume in advance the number of items to permutate and will have difficulty in handling the case when the number of elements to permutate is dynamic.
First of all, you need to understand what a stack is, that is a Last In, First Out (LIFO) data-structure, which means that you can always push elements to its top, but whenever you need to take out an element, you take it to the top.
So, you need to implement the following (I'm not taking the fun of the actual implementation):
you create an empty stack
you add 1 to its top
while your stack is not empty
if you are not at the last element, push the first element that's not already in the stack
else if you are at the last element, then you have found a new permutation and
while stack.top is n or there is no stack.top < i <= n that's not already in the stack, stack.pop
if the stack is empty, then the algorithm ends
else
current <- stack.top
stack.push(the first element that's higher than current and is not in the stack)
So, you are able to use one main loop and inside that loop you will only need some loops to find the next unused element instead of a loop for every index.

Modify LinkedList after traverse

I am using a LinkedList, I need to add an element to the LinkedList immediately after traversing it.
I mean, let's suppose I have a LinkedList of unsorted integers.
LinkedList<Integer> list = new LinkedList<>();
list.add(4);
list.add(2);
list.add(5);
I want to add a zero after each even number.
var itr = list.listIterator();
while (itr.hasNext()) {
int i = itr.next();
if (i % 2 == 0) {
itr.add(0);
}
}
After executing this, I get the LinkedList containing: [4, 0, 2, 0, 5]
Now suppose I want to add a zero only after the smallest even number.
I know I can first search the smallest even number traversing the LinkedList in O(n) and then using the .add(index, element) to add the zero after the smallest even number. The add(index, element) method runs in average O(n) since it needs to traverse some nodes of the list, I would like to avoid it and perform my operation of adding a zero after the smallest even number in a single traverse. Is that possible?
Update
Thanks so much guys for your answers. I'll try to write a pseudocode, I think if I was working with a custom double linked list the problem could be solved in the following way
Node smallest = new Node(99998); // reference to smallest even number
While (current != Null){
If (current.value %2 == 0 && current.value < smallest.value){
smallest = current:
}
current = current.next:
}
// Link zero after smallest even number in constant time
Node zero = new Node (0);
zero.prev = smallest;
zero.next = smallest.next;
smallest.next = zero:
smallest.next.prev = zero;
Something like that. What do you think about it?
Though it might not be the most efficient, but you might use two iterators.
First for list traversal
Second for smallest numbers traversal
The issue is, when the smallest number is found, then the second iterator must catch up with the first iterator, so you end up calling Iterator#next() n-times, where n is difference between indices of the old and the new smallest number.
while (itr.hasNext()) {
int i = itr.next();
if (i % 2 == 0 && i < smallest) {
smallest = i;
while (smallestItr.nextIndex() != itr.previousIndex()) {
smallestItr.next();
}
}
}
System.out.println(smallestItr.next())
Otherwise, I would say if you need to put number into specified index in reasonable time complexity, use reasonable data structure for it.

Java Code More Efficient

I am creating a code here but I believe there is a way making the following more efficient. I tried many ways but it does not seem to work.
protected void randomise() {
int[] copy = new int[array().length]; //This makes the new int called randomIndex
// used to indicate if elements have been used
boolean[] used = new boolean[array().length]; //calling "used" as a new boolean for the array
Arrays.fill(used,false);
/**
* if index = 0, it means their is nothing in the index.
* if you apply a random number, it will copy that number to an array called index.
* if randomIndex in use, then the boolean becomes true.
*/
for (int index = 0; index < array().length;) {
do {
randomIndex = randomIndex();
} while (used[randomIndex]); //when random is in use, do the follow instruction.
copy[index] = array[index]; //copy the value value to an array called index.
used[randomIndex] = true; //when randomIndex is in use, then it becomes true.
}
//Of course, if there an extra random stores in the array, the index list is increased by one (index++).
for (int index =0;index < array().length; index++) {
array()[index] = copy[index]; //This tells where to copy the index value. in this case, it is a index array.
}
Do you have to use randomIndex?
If not you can use your bool[] to eliminate that do {} while() by sequentially adding the value to copy (which isn't a great name) and choosing a randInt in the range of the len of elements that haven't been selected, then using that bool[] to count a walk through the array elements ( to make your choice for the next element in copy.
You seem to want to randomly re-order an array. If so, then indeed there is a much more efficient solution. You are currently keeping two extra arrays on the size of the input (O(n)) while you do not have to.
The random shuffling is a common problem, and obviously there have been proposed several algorithms to accomplish this task. One of the most efficient algorithms is Knuth's algorithm for random permutation
The algorithms idea is, loop over the array once, and for each number i, perform a random exchange between i and a (random) array index between 0 and i. This guarantees that the array with be shuffled (meaning that each item will have equal possibility to be placed in each of the array indexes), in O(n) time and without using any extra space.
In short,
for (int i = 0; i < index; i++) {
int r = random.nextInt(i + 1);
exchange(array, i, r);
}
It is simple - use some collection of indexes and remove element when you used it. This way should looks like:
List<Integer> indexes = new ArrayList<>(array.length);
for (int i = 0 ; i < array.length ; i++) {
indexes.add(i);
}
Random r = new Random();
while (indexes.size() > 0) {
int randomIndex = r.nextInt(indexes.size());
int index = indexes.remove(randomIndex);
copy[index] = array[index];
}
Please note that:
you should check what is exact collection will be more efficient in your situation
Another way - create list values for array and use Collections.shuffle method on this list.
Additional another way - use some recursive algorithm to do that work.

organizing numbers in an array in Java [duplicate]

This question already has answers here:
Sort an array in Java
(19 answers)
Closed 9 years ago.
Im trying to organize random numbers in an array from least to greatest.
I came up with a loop which I thought should work but has a lot of logic errors.
for(int z=0; z<=999;z++){
for(w=1; w<=999;w++){
if(z<w){
if(numberArray[z]<numberArray[w])
temp=numberArray[w];
}
}
numberArray[z]=temp;
}
Can anyone tell me how to fix this or an algorithm of their own for doing this?
There are several ways you can sort an array in Java. Here I post but 3 of them : the core library, and 2 algorithms you can make on your own.
1 ) Core one: This is literally only one line of code. I would suggest using this - simple, and very efficient, compared to the below two solutions.
Arrays.sort(myArray);
2 ) Selection Sort : Find the lowest value in an array, move it to the first position, find the next lowest, move to 2nd position, etc.
public void selectionSort(Comparable[] a)
{
for(int index = 0; index < a.length; index++)
{
// find the smallest one in the array from index : end
int smallest = indexOfMin(a, index);
// swap the value at index and the value at the smallest one found
Comparable temp = a[smallest];
a[smallest] = a[index];
display.update();
a[index] = temp;
}
}
3 ) Insertion Sort : Inserts each element in the array into a growing sequence of sorted values and finishes at the end of the array.
public void insertionSort(Comparable[] a)
{
for(int i = 1; i < a.length; i++)
{
insert(a, i);
}
}
public void insert(Comparable[] a, int nextIndex)
{
int index = 0;
Comparable finalObject = a[nextIndex];
// Let us first find the first occurence of a comparable greater than our comparable
while(finalObject.compareTo(a[index]) > 0)
index++;
for(int i = (nextIndex-1); i >= index; i--)
a[i+1] = a[i];
a[index] = finalObject;
}
One liner:
Arrays.sort(numberArray);
Or greatest to least order:
Arrays.sort(numberArray, Collections.reverseOrder());
Or even better, use a Binary Search Tree that keeps its contents in sorted order, this is great for collections that are pretty dynamic, as the add operation is cheaper memory wise and time wise than a full in-place sort:
TreeSet<int> set = new TreeSet<int>();
set.add(10);
set.add(4);
set.add(11);
set.toString();
// prints 4, 10, 11
Arrays.sort() is a quick and easy way.
Also consider PriorityQueues if you need something a little more robust!
This link is another question on SO with a great answer.

How can I (more) easily compare two sets of numbers?

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);
}
}

Categories