I really need help with a homework problem. I've been trying to figure this out for days and would really appreciate some assistance! Here's the prompt:
Merge two arrays into one. Write a method named merge which takes 3 interger array
parameters: a, b, and soln. soln is guaranteed to be the size of a.length + b.length. The arrays a and b should be "merged" into one array by alternating elements. Add a 4th parameter, which indicates which element in soln should be updated for a given recursive call of the method.
Examples:
merge({1, 2, 3}, {4, 5, 6}, soln, 0) should end with the following values in soln: {1, 4, 2, 5, 3, 6}
merge({1,2}, {3,4,5}, soln, 0) should end with the following values in soln: {1,3,2,4,5}
I can get it to work with the arrays are the same length, and even when the arrays differ in length (but only by one element). I can't get the index to line up correctly. I've tried many different variations, but here's what I have so far:
public static void merge3(int[] a, int[] b, int[] soln, int index) {
if (index > soln.length-1) {
return; //if index reaches end of soln length
}
int index2 = (int)(index/2); //allows me to pull alternately from a and b arrays. As index goes up, index2 becomes 0, 0, 1, 1, 2, 2, etc.
if (b.length >= a.length) {
if (index%2 == 0) {
if (index2 > a.length-1) {
soln[index] = b[index2];
merge3(a, b, soln, index+1);
} else {
soln[index] = a[index2];
merge3(a, b, soln, index+1);
}
} else {
soln[index] = b[index2];
merge3(a, b, soln, index+1);
}
} else if (b.length < a.length) {
if (index%2 == 0) {
soln[index] = a[index2];
merge3(a, b, soln, index+1);
} else {
if (index2 >= b.length) {
soln[index] = a[index2];
merge3(a, b, soln, index+1);
} else {
soln[index] = b[index2];
merge3(a, b, soln, index+1);
}
}
}
}
If array a is {1, 2, 3} and array b is {4, 5, 6, 7, 8, 9}, soln becomes {1, 4, 2, 5, 3, 6, 7, 7, 8} instead of what it's supposed to be, which is {1, 4, 2, 5, 3, 6, 7, 8, 9}. It's off because when I do index + 1, the recursive call catches on the same value (index2) which was used to alternate between the arrays when there's only one array left. Please help! Thank you!
Here is an intentionally pedantic approach to thinking through this kind of problem.Start by determining your state. One way to divide all the possibilities in this problem into distinct states is:
exit, where you will simply return. (always need this for every recursively called method).
before array exhaustion, where you still have at least one array element left in each of the input arrays a and b.
after array exhaustion, where all of the smaller array's elements have already been added to soln
array a empty where the first array has no elements. Normally you would handle this outside a recursive call, but we're following rules here...
Each of these states represents a different way that you need to handle your inputs.
The pseudocode for this type of structure would look like:
if (test to see if we're in "exit" state) {
logic handling "exit" state
} else {
if (test to see if we're in "before array exhaustion" state) {
logic handling "before array exhaustion" state
} else {
if (test to see if we're in "array `a` empty" state ) {
logic handling "array `a` empty" state
} else {
logic handling "after array exhaustion" state
}
}
}
recursive call to your method here
You already have the (test to see if we're in "exit" state) here:
if (index > soln.length-1) {
and you have the logic handling "exit" state here:
return; //if index reaches end of soln length
Since this state's logic returns, the syntax doesn't require that you put it in an if-else like it is in the pseudocode, but it might be clearer while you're getting a handle on Java syntax if you consistently use the if-else structure throughout.
After that you need your if (test to see if we're in "before array exhaustion" state), conditional, but instead your code assumes you're at logic handling "before array exhaustion" state and handles it accordingly. The logic is good, but the state isn't. You'll need to use the template and put that logic in its proper place, but at least you don't have to rewrite it.
Now fill out the rest of the pseudocode template, starting with the tests.
Tests:
The test to see if we're in "array 'a' empty" state just looks to see if array a is empty or not, so it's pretty trivial to write.
The test to see if we're in "before array exhaustion" state checks whether we've already copied all of the smaller array's elements into soln yet or not, based on a.length, b.length, and index.
Array population logic:
What you've got below your exit case works perfectly for logic handling "before array exhaustion" state, so you just need to write:
logic handling "array 'a' empty" state where you already know array a is empty.
logic handling "after array exhaustion" state. This is the part where we're all done with the smaller array, and we need to know which element to pull from the larger input array so that we can add it to soln.
So basically follow the template and write the 3 tests (1 already done, one trivial, and one more), and then write the logic for the different states (two already done, one trivial, and one more) and you're there.
You might also consider refactoring your existing code so that there's only one recursive call that happens at the very end. That's called tail recursion, and even with all the optimizations that Java SE 8 has, it's still better this way. It's also a lot cleaner.
Hopefully this is a useful template for thinking through a simple problem.
Related
I'm trying to generate an array of 5 non-repeating integers in Java, but there are still repeats when I run it. Here's my code so far:
public int[] generateCode(){
code[0] = (int)Math.round(Math.random()*8+1); // initialize first number so it won't be compared against
for(int i=1; i<code.length; i++){
code[i] = (int)Math.round(Math.random()*8)+1;
for(int j=0; j<i; j++){
while(code[i]==code[j]){
code[i] = (int)Math.round(Math.random()*8)+1;
}
} // end inner for loop
} // end outer for loop
return code;
} // end generateCode method
Any help is very much appreciated!
So, your for-loop is checking for repeated characters, BUT each time you generate a new value (in the while-loop) you're not checking to see if the value exits before j.
There are a number of possible ways you might address this issue, I prefer ones which uses Collections.shuffle, but assuming that you can't use features like Arrays, Collections, List, Set or possibly even streams, we need to work with what we have, arrays.
Since you have a small range of acceptable values which need to fit into an even smaller range, a simple solution might be to generate a "master" list of allowed values and randomly select a value from the master list, tracking which values you've already picked.
Sounds more complicated then it actually is, for example...
public int[] generateCode() {
int[] masterValues = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int[] codes = new int[5];
Random rnd = new Random();
int index = 0;
while (index < codes.length) {
int lookupIndex = 0;
do {
lookupIndex = rnd.nextInt(masterValues.length);
} while (masterValues[lookupIndex] == 0);
codes[index] = masterValues[lookupIndex];
masterValues[lookupIndex] = 0;
index++;
}
return codes;
}
This creates a "master" list of values. It then randomly calculates a "lookup" index, checks to see if the value in the master list is 0 or not, if not, it assigns it to the next index in the codes array and sets the value in the master list to 0, otherwise it generates a new random index and tries again. This all repeats till it fills the codes array
So doing something like...
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
System.out.println(Arrays.toString(generateCode()));
could print (because it's "random")...
[8, 1, 4, 7, 5]
[9, 6, 2, 1, 8]
[6, 5, 9, 4, 7]
[2, 5, 3, 1, 4]
There are much easier ways to do this. Using a Set<Integer> would be one. Here is another.
List<Integer> list = new ArrayList<>(List.of(1,2,3,4,5,6,7,8));
Collections.shuffle(list);
System.out.println(list.subList(0,5));
prints something like
[4, 5, 8, 2, 1]
As was pointed out to me, you may not be allowed to use or know about collections. But I would recommend you at least make a helper method to check for duplicates to reduce the clutter. Something like the following:
public boolean contains(int[] arr, int n) {
for (int v : arr) {
if (v == n) {
return true;
}
}
return false;
}
Then you can keep checking the current value to be false before you add it. Once it works it also lets you focus on other aspects of your code.
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 have an integer array of size 4. I am adding elements to it via the add method. This is as an unsorted array. I am sorting it via the sort method shown in the code below. The sort method places the smallest number in the position a[0]. When I try to add elements after I call the sort method I always get a return value of 0. Is there a way around this?
import java.util.Arrays;
public class Scrap {
private static int[] array = new int[4];
private static int i = 0;
public static void main(String[] args) {
Scrap pq = new Scrap();
pq.add(4);
pq.insert(3);
pq.add(5);
pq.sort();// smallest to largest sort method.
// System.out.println(array[0]);
pq.insert(1);
pq.sort();
int test = pq.Minimum();
System.out.println("The smallest element of the array is " + test);
pq.sort();
}
//
public void add(int input) {
insert(input);
}
// Method to insert number into the array.
public void insert(int input) {
array[i] = input;
i++;
}
// Finding smallest number of the array.
public int Minimum() {
int a = array[0];
return a;
}
// Sorts the array from smallest to largest integer
public void sort() {
int first, temp;
for (int i = array.length - 1; i > 0; i--) {
first = 0;
for (int j = 1; j <= 1; j++) {
if (array[j] > array[first])
first = j;
}
temp = array[first];
array[first] = array[i];
array[i] = temp;
}
}
public int remove() {
return delete();
}
public int delete() {
return remove();
}
// Method to convert the array into a string for output
}
The problem in a nutshell:
You start with an array of length 4.
At this point the array contains 4 zeros, that is: [0, 0, 0, 0]
You add 4, 3, and 5. These operations update the content of the array to [4, 3, 5, 0].
You sort the array. This should change the content of the array to [0, 3, 4, 5]. In fact it changes to [0, 5, 3, 4], which means your implementation of sort is clearly broken.
You probably didn't expect the 0 value to move. You can fix this by sorting only the first 3 values. (And, of course, you should also fix your implementation of sort.)
Then when you insert 1, the program updates the value at index 3, so the content changes to [0, 5, 3, 1].
If you implement the fix I suggested above, and sort only the first size elements, then the content after the first call to sort should become [3, 4, 5, 0], and the content after the insert 1 should become [3, 4, 5, 1]. And when you sort that again, the content should become [1, 3, 4, 5] and the smallest value will be 1 as expected, instead of 0.
More concretely:
First of all, change private static int i = 0; to private int size = 0;. The name i is extremely inappropriate here, and will surely confuse you. size is appropriate. It also doesn't make sense to make it static, so I suggest to drop that keyword.
Fix the implementation of sort. There are many basic sorting algorithms that are easy to implement. In the implementation, instead of going until array.size, go until size. Do you see the difference? size is the field in Scrap, essentially it's the number of elements you added using the add or insert methods.
Some cleaning up would be good too:
Delete the add method and rename insert to add.
Delete the remove and delete methods. They are not used, and you will get a stack overflow if you try to use them as they are now (the methods call each other, forever)
Look at the content of the array after each step in the program.
After Scrap pq is created, this is the content of its array:
[0, 0, 0, 0]
Then a couple of modifications:
pq.add(4);
pq.insert(3);
pq.add(5);
The content at this point:
[4, 3, 5, 0]
So far so good.
Then you sort it:
pq.sort();
The content at this point:
[0, 5, 3, 4]
Ouch. The sort implementation doesn't work very well, does it. But let's ignore that for now. Next step:
pq.insert(1);
The content at this point:
[0, 5, 3, 1]
None of this behavior makes sense, probably this is not how you intended the program to work. Review the program, verify the content after each step. Do not proceed to the next step until the current step is working correctly.
I am assuming that you will be using a correct sort method (because, this is not correct, you can use Arrays.sort). But still with a correct sort, there is a logical problem in your code.
At the beginning, the array contains all 0s. After adding the first 3 int, when you call the sort method, the array contains the values in following order:
0,3,4,5
Note that, the value of i is not changed. At this state the value of i is 3. So when you insert 1, the new values become
0,3,4,1
So after sorting again, the values of arrays become
0,1,3,4
So obviously the minimum will retrun 0
I don't think that is the most effective way to sort an array. It is possible to do this with just 1 for loop. Try this to sort your array from smallest to largest.
int temp;
for(int i=0;i<array.length-1;i++){
if(array[i]>array[i+1]){
temp=array[i];
array[i]=array[i+1];
array[i+1]=temp;
i=-1;
}
}
I have quite a layman question about Java programming.
I would like to write a function to check whether a list of number is sequential or not.
Say [1, 2, 3, 4, 5], the function will return true,
but for [1, 3, 4, 9, 10], the function will return false.
Could anyone help me?
Thank so much!
Write a loop that looks at each element of the list.
For each position i in the list, test that listi + 1 equals listi + 1.
You can code it yourself as an exercise. (Don't forget to deal with the edge cases ...)
UPDATE: ... for people treating this problem as a learning exercise.
A simple direct implementation approach is probably the best idea; e.g. #Joe's final answer. However, the simple approach doesn't always work well ... or at all:
Some Java List implementations have a get method that is O(N). That would lead to an O(N^2) algorithm overall.
Sometimes a a list can only be accessed using an iterator; i.e. list.get(i) might not be an option.
In such cases, you could implement the algorithm with one pass through the list using an iterator. You need to keep "the previous element" in variable, etcetera.
Logic is simple. Just get the first number and check whether it matches with the next value. Like that check adjacent values. Break if the condition fails at any point. The list will be sequential if all the if condition is true.
As Stephen C said, it is a very simple logic
int a[] = { 1, 2, 3, 4, 5,7 };
boolean flag = true;
for (int i = 0; i < a.length - 1; i++) {
if (a[i + 1] != a[i] + 1) {
flag = false;
break;
}
}
System.out.println("Flag is " + flag);
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.