I'm working on a project where I need to use recursion, and arraylists/vectors to solve a 3-satisfiability instance. The task is to select a sub-set of integers, such that each set denoted below contains one or more elements of the sub-set. The constraint being that a number, i & its opposite, -i, cannot both be in the sub-set.
Vector<Vector<Integer>> matrix = new Vector<Vector<Integer>>();
for(int i=0;i<4;i++)
{
matrix.add(new Vector<Integer>());
}
the 2-dimensional vector/arraylist is then filled with numbers, for example:
1, -2, 3
-1, 2, 4
2, -3, 4
-1, -2, -3
if(startRec(matrix)
{
//solution is found
}
else
{
//no solution is possible
}
private boolean startRec(Vector<Vector<Integer>> matrix)
{ // I'm using trial and error to find a solution to the above problem. So in the below, matrix.get(0).get(i) is selected as part of a possibly correct set.
boolean success=false;
if(stagen(matrix.get(0).get(0), matrix))
{
success=true;
}
else if(stagen(matrix.get(0).get(1),matrix))
{
success=true;
}
else if(stagen(matrix.get(0).get(2),matrix))
{
success=true;
}
return success;
}
private boolean stagen(int input, Vector<Vector<Integer>> matrix)
{
removei(input, matrix) // this removes all Vector<Integer> that contain i. Those sets are considered satisfied, and no longer need to be addressed.
removenegative(input,matrix) // this removes all integers that are -input. Since i and -i cannot both be selected, I'm removing the -input.
//So if a set contained three ints, one of which was -input, it now contains 2.
boolean success=false;
if(stagen(matrix.get(0).get(0), matrix)) // since the original matrix.get(0) contained input, it was removed in removei(input,matrix), thus this is a one below the one called previously.
{
success=true;
}
else if(stagen(matrix.get(0).get(1),matrix))
{
success=true;
}
else if(stagen(matrix.get(0).get(2),matrix))
{
success=true;
}
return success;
}
I've removed the out of range checks, to make it more readable. But the process I'm confident is going on is this:
1, -2, 3 //1 is selected in the second line of startRec
-1, 2, 4
2, -3, 4
-1, -2, -3
//1, -2, 3 line is removed from consideration by method removei() as 1 has been selected
2, 4 // -1 has been removed as both 1,-1 cannot be selected.
2, -3, 4
-2, -3 // -1 removed.
2, 4 now 2 is the first number, so 2 is selected.
-2, 3, 4
-2, -3
//2, 4 removed via removei method.
3, 4 //-2 is removed, because 2 has been selected.
-3 //-2removed.
3, 4 //Now 3 is selected.
-3
//3, 4 line removed as it has been satisfied.
_____ //There's now an empty set here as -3 was deleted
//false is returned by stagen.
The program returns to the stagen which selected 3, and it now ideally now select 4 as the next letter. But I deleted that whole row.
Is there a way to do this without creating an unknown number of vectors?
2ndly, is there a significant difference between arraylists & vectors? I've been using arraylists, exclusively, but the project suggests vectors.
The first part of your question is incoherent. However I'll elaborate on the differences between Vector and Arraylist:
If multiple threads access an ArrayList concurrently then you need to externally synchronize the block of code which modifies the list.
Internally, both of them use an array to maintain the data structure. If running out of space, ArrayList increases its size by 50% while Vector doubles its size.
Refer this thread for a detailed explanation.
Related
I have an array:
int[] arr = {-4, -2, -1, 0, 1, 3, 4, 5, 6, 9, 10, 12, 13, 14, 18};
The array is ordered in ascending order.
The main idea is to get elements and group them, where next element is greater than a previous by 1. The minimum length of such elements should be equal 3.
In output, I have to get a string:
"-4, (-2-1), (3-6), 9, 10, (12-14), 18"
The first interval is:
-2, -1, 0, 1 - it should looks like range i.e -2-1
The next interval is:
3, 4, 5, 6 - it should looks like range i.e 3-6
9, 10 - the length is less than 3
So the last interval is:
12, 13, 14 it should looks like range i.e 12-14
this answer was pre-edit.
You are printing input[i] but you are expecting the values in input[i] - 1
when you run this in the debugger you can see it finds -1 (which has -2 before it, and equals -2 + 1). You then print the -1 you found.
If you want the output to contain the -2 , you should print input[i - 1]
post-edit:
you have grouped elements by braces which means you are looking for a sequence. This will require you to keep the start number somewhere. the code you originally posted (simple loop that checks left) will need a bit more work.
In rough terms:
if (continuing a range)
if(this number is still in range / +1) continue
else: stop the range and print it (start point plus current -1). if current -1 is the start point, don't use braces and range indicator. if it is different use braces and - between start and end)
else
start a range. (keep track of the number you are on and continue.
that's what you need in pseudocode
Algorithm
You could loop through the array.
If found consecutive number, add it to a group (e.g. List).
If group satisfies minimum length (e.g. 3) then add it to output formatted as range (and clear the group).
If no consecutive number, just add it to output.
Code
public static String formatAsRange(List<Integer> list) {
return String.format("(%d-%d)", list.get(0), list.get(list.size()-1));
}
public static String consecutiveElements(int[] array, int minGroupLength) {
StringBuilder sb = new StringBuilder();
List<Integer> group = new ArrayList<>();
for(int i = 0; i < array.length; i++) {
if (i == 0 || array[i] == array[i-1] + 1) {
group.add(array[i]);
} else {
if (group.size() >= minGroupLength) {
sb.append(formatAsRange(group)).append(',');
} else {
var csv = group.stream().map(String::valueOf).collect(Collectors.joining(","));
sb.append(csv).append(',');
}
group.clear();
sb.append(array[i]).append(',');
}
}
return sb.toString();
}
For your input it prints:
-4,-2,(-1-1),3,(4-6),9,10,12,13,14,18,
See the demo on IDEone.
To do
So there is still something to fix. For example
expected range 12-14 is missing
expected range -2-1 is not complete with -2, (-1-1)
expected range 3-6 is not complete with 3, (4-6)
the last comma can be removed
can add a space following each comma
I am working through sample questions for the Computer Science A exam and cannot figure out why the correct answer is correct on the following problem.
Consider the following method.
public static void mystery(List<Integer> nums)
{
for (int k = 0; k < nums.size(); k++)
{
if (nums.get(k).intValue() == 0)
{
nums.remove(k);
}
}
}
Assume that a List values initially contains the following Integer values.
[0, 0, 4, 2, 5, 0, 3, 0]
What will values contain as a result of executing mystery(values)?
The correct answer showing is : [0, 4, 2, 5, 3]
Why does the first 0 remain in the list?
The first 0 remains because that was really the second 0 in nums.
When k is 0, the test succeeds and remove(0) is called, removing the first index. That shifts all the other elements down, so that the list is now [0, 4, 2, 5, 0, 3, 0]. But then k is incremented to 1, so the second 0 (now at index 0) is skipped and not removed.
The other 0 values are removed successfully, just as the first 0 is removed successfully. This code skips only the second of two consecutive 0 values. This would be a bug, assuming that the code is supposed to remove all 0 values.
The answer already given by #rgettman is correct. However, I'd like to add that this is a particular example of a common issue - that of modifying a sequence (collection, whatever) while iterating (indexing, whatever) through it. You need to understand the effect that the modification will have on the in-progress iteration. And sometimes the effect is formally given as "undefined", i.e., you don't want to do it.
For Java, the Iterator<> class has a remove() method that safely removes the current element. If you actually wanted to remove all zeroes from your List<>, rather than just explaining what is happening in the test question, then Iterator would be one way to go about it.
I see a lot of posts with the same topic (mostly with Strings) but haven't found the answer to my question. How would I remove duplicate integers from an ArrayList?
import java.util.*;
public class ArrayList2 {
public static ArrayList<Integer> removeAllDuplicates(ArrayList<Integer> list) {
Collections.sort(list);
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == list.get(i + 1)) {
list.remove(i);
}
}
return list;
}
}
This is the start of my code, the only problem that has arised is that if there are 3 integers with the same value, it only removes one of them. If I put in 4, it removes two of them. PLEASE NO HASHING!!!
The ArrayList and the output when I run it:
List: [-13, -13, -6, -3, 0, 1, 1, 1, 5, 7, 9]
Duplicates Removed: [-13, -6, -3, 0, 1, 1, 5, 7, 9]
This is my first time using this website, so please let me know if I'm doing something wrong with formatting/if there's already an answer to my question that I missed.
The specific reason why your removeAllDuplicates function doesn't work is that you are still iterating after a successful comparison. If you iterate only when list.get(i) != list.get(i + 1), you will get rid of all the duplicates.
public static ArrayList<Integer> removeAllDuplicates(ArrayList<Integer> list) {
Collections.sort(list);
int i = 0;
while(i < list.size() - 1) {
if (list.get(i) == list.get(i + 1)) {
list.remove(i);
} else {
i++;
}
}
return list;
}
It's worth noting that the above function is not as fast as it could be. Though the iteration runs quickly enough, the most significant step will be the sort operation (O(n log n)).
To avoid this extra time complexity, consider using a HashSet instead of an ArrayList (if it still fits within the constraints of your problem).
Other people have "answered" the basic issue, of the if statement skipping over elements because the for-loop is incrementing the index position, while the size of the array is shrinking.
This is just "another" possible solution. Personally, I don't like mutating Lists in loops and prefer to use iterators, something like...
Collections.sort(list);
Iterator<Integer> it = list.iterator();
Integer last = null;
while (it.hasNext()) {
Integer next = it.next();
if (next == last) {
it.remove();
}
last = next;
}
Still, I think some kind of Set would be a simpler and easier solution (and since you'd not have to sort the list, more efficient ;))
This assumes that you cannot use a set ("Please No hashing!!!") for a reason such as homework.
Look what happens when you remove a duplicate. Let's say that the dupe you're removing is the 1st of 3 consecutive equal numbers.
v
-13, -6, -3, 0, 1, 1, 1, 5, 7, 9
Here i is 4 to refer to the first of the 3 1 values. When you remove it, all subsequent elements get shifted down, so that the second 1 value now takes the place of the first 1 value at index i = 4. Then the current iteration ends, another one begins, and i is now 5.
v
-13, -6, -3, 0, 1, 1, 5, 7, 9
But now i is referring to the second of the two 1 values left, and the next element 5 isn't equal, so no dupe is found.
Every time you find a duplicate, you must decrease i by 1 so that you can stay on the first element that is a duplicate, to catch 3 or more duplicates in a row.
v
-13, -6, -3, 0, 1, 1, 5, 7, 9
Now consecutive elements still match, and another 1 value will get removed.
You'd want to have a double for loop as you dont want to check the only the next index but all indexes. As well as remember when you remove a value you want to check that removed value again as it could of been replaced with another duplicate value.
This is what I coded myself and I understand everything what is done here:
import java.util.Arrays;
public class Decision{
public static void main (String[]args){
int[] myArray = {1,8,3,0,2};
for(int i=0; i<myArray.length-1; i++){
if(myArray[i]<myArray[i+1]){
}
else{
int temp=myArray[i];
myArray[i]=myArray[i+1];
myArray[i+1]=temp;
}
System.out.println(Arrays.toString(myArray));
}
}
}
Output: [1, 3, 0, 2, 8]
So we first check if the first value in the array is smaller than the next one. If yes, then don't do anything. If not, then swap both.
The problem with this sort algorithm is that it won't swap as example the first value with the third one, or the second with the fifth, etc.
I realized this sort works perfectly if we add a second for-loop that repeats the for-loop in my code:
for(int n=myArray.length; n>1; n=n-1){
...
}
I also realized this kind of sort is called bubble sort, but please explain me the important role of this for-loop, I'm sad I cannot understand what it does at all? : /
In all honesty I'm a bit confused about your question. Normally I'd recommend adding diagnostics printouts, but you already have one. As you can see, doing only one pass can at most swap an item with the one next to it. There's no way you can fully sort the array this way, because once you process one element at [i], your algorithm of course can't move that element anywhere else. So if it's not in its final correct position after that one pass, it'll never get there. In particular, a given element can only be moved to the left at most 1 position per pass. The worst case of this is if the input is sorted in decreasing order before going in.
When you add an outer loop doing multiple passes, it sorts the array a little bit more each time, until finally it's sorted. Doing myArray.length - 1 passes guarantees that even the worst-case elements get a chance to be "moved" through the entire array to their correct position, because in the worst case input it guarantees that you'll be able to move an element left through the entire array (in an array of length n it takes n-1 moves to get the element in the last position into the first position -- if this doesn't click, draw it on paper and count).
I mean, there is an important skill missing from your toolset that you really ought to learn, which is that you need to get used to visualizing what your code does. There are a few ways to do this:
Research the algorithm you are implementing. The linked wiki article on bubble sort pretty clearly explains the algorithm in the step-by-step section.
With some experience it will make sense in your head.
Work things out on paper.
Trace through things line-by-line in your debugger.
Add temporary trace print-outs to your programs.
And of course, sometimes experimenting with algorithms by breaking them and observing the changes.
You went with #5 and #6, you just need to learn how to interpret the information. Here is a working version of your sort, for example (ignoring other potential code improvements, I am certain other answers here will help you along those line) with one extra print added to separate the passes in the output:
public static void main (String[]args){
int[] myArray = {1,8,3,0,2};
for(int n=myArray.length; n>1; n=n-1){
System.out.println("Outer loop: " + n);
for(int i=0; i<myArray.length-1; i++){
if(myArray[i]<myArray[i+1]){
}
else{
int temp=myArray[i];
myArray[i]=myArray[i+1];
myArray[i+1]=temp;
}
System.out.println(Arrays.toString(myArray));
}
}
}
This outputs:
Outer loop: 5
[1, 8, 3, 0, 2]
[1, 3, 8, 0, 2]
[1, 3, 0, 8, 2]
[1, 3, 0, 2, 8]
Outer loop: 4
[1, 3, 0, 2, 8]
[1, 0, 3, 2, 8]
[1, 0, 2, 3, 8]
[1, 0, 2, 3, 8]
Outer loop: 3
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
Outer loop: 2
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
[0, 1, 2, 3, 8]
As you can see, after the first pass it's not fully sorted. The second pass is a bit closer. The third pass completes it in this case. It's the 0 that's holding things up in this case: The 0 has to move left 3 positions, and so you must complete at least 3 passes.
For an even clearer picture try that ideone example with the worst case input of [8, 3, 2, 1, 0].
Assume the worst case for this algorithm, an array sorted in reverse order and see what happens with one loop
4 3 2 1 0 original array
3 4 2 1 0 after one swap
3 2 4 1 0 after two swaps
3 2 1 4 0 after three swaps
3 2 1 0 4 after the complete loop
You see that only the largest element is now in the right place, all the rest is still in reverse order. After a second pass the second largest element will be in the correct place as well and so on.
Note that the passes after the first do not have to go over the full array (but it does not hurt) because more and more elements will already have reached their final position.
Instead of adding the 2nd loop you could also say
boolean change = true;
while (change) {
change = false;
...
if (a[i] > a[i + 1]) { // write it like this and you don't need an else
change = true;
// swap
}
...
}
Both work, because the maximum number of passes needed to sort the array is n - 1. For the worst case, an array sorted descending instead of ascending, the elements will wander to the end like water bubbles to the top of the water. On the first iteration the first element will end up in the last position, on the 2nd iteration the originally 2nd element (now first) will travel up to the 2nd last position and so on. So you can see that you need only n-1 iterations, because on the (n-1)th iteration the originally 2nd last element (now the first) will end up in 2nd position and the originally last element (now the first) is already sorted correctly.
You can also notice, that on each iteration (at least) one more element at the end of the array ends up in its correct position, so you can decrease the max for the inner loop on each iteration.
I've got a set of recursion problems that I need to do. I've completed 3 out of the 4 of them we were given, but I'm having a hard time wrapping my head around this last one. I don't necessarily want the actual answer, but maybe just point me in the right direction, because I'm not even seeing what my stop condition should be on this one. And note, it has to be recursive, no loops, etc.
Thanks in advance for any help provided!
Write recursive method arrayRange that returns the maximum integer minus the minimum integer in the filled array of ints. Use recursion; do not use a loop. The following assertions must pass (note the shortcut way to pass a reference to a new array--it saves your writing a bit of code (this passes an array built as a parameter):
assertEquals(2, rf.arrayRange(new int[] { 1, 2, 3 } ));
assertEquals(2, rf.arrayRange(new int[] { 3, 2, 1 } ));
assertEquals(0, rf.arrayRange(new int[] { 3 } ));
assertEquals(3, rf.arrayRange(new int[] { -3, -2, -5, -4 } ));
// Precondition: a.length > 0
public int arrayRange(int[] a)
The stop condition is when there are only two items left: the maximum and minimum. Then just return the difference. (Also handle the case of 1 or 0 items, consider input such as in the test cases.)
Now .. how to reduce the list each pass? :) I would consider inspecting the first three values at a time (of the three, only two should remain in the recursive step).
Happy homeworking.