This is a hw assignment technically but I am doing it for practice not for a grade. Here is the problem with my solution so far:
/**
* smoosh() takes an array of ints. On completion the array contains the
* same numbers, but wherever the array had two or more consecutive
* duplicate numbers, they are replaced by one copy of the number. Hence,
* after smoosh() is done, no two consecutive numbers in the array are the
* same.
*
* Any unused elements at the end of the array are set to -1.
*
* For example, if the input array is [ 0 0 0 0 1 1 0 0 0 3 3 3 1 1 0 ], it
* reads [ 0 1 0 3 1 0 -1 -1 -1 -1 -1 -1 -1 -1 -1 ] after smoosh()
* completes.
*
* #param ints
* the input array.
**/
public static void smoosh(int[] ints) {
// Fill in your solution here. (Ours is fourteen lines long, not
// counting
// blank lines or lines already present in this file.)
int index = ints.length - 1;
for (int i = 1; i < ints.length; i++) {
if (ints[i] == ints[i - 1]) {
for (int j = i; j < ints.length - 1; j++) {
ints[j] = ints[j + 1];
}
ints[index] = -1;
index--;
}
}
}
EDIT: updated code here is my results:
Let's smoosh arrays!
smooshing [ 3 7 7 7 4 5 5 2 0 8 8 8 8 5 ]:
[ 3 7 7 4 5 2 0 -1 -1 -1 -1 -1 -1 -1 ]
*** ERROR: BAD SMOOSH!!! No cookie.
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Unknown Source)
at hw3.TestHelper.verify(TestHelper.java:26)
at hw3.Homework3.main(Homework3.java:72)
smooshing [ 6 6 6 6 6 3 6 3 6 3 3 3 3 3 3 ]:
[ 6 6 6 3 6 3 -1 -1 -1 -1 -1 -1 -1 -1 -1 ]
*** ERROR: BAD SMOOSH!!! No cookie.
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Unknown Source)
at hw3.TestHelper.verify(TestHelper.java:26)
at hw3.Homework3.main(Homework3.java:82)
smooshing [ 4 4 4 4 4 ]:
[ 4 4 -1 -1 -1 ]
*** ERROR: BAD SMOOSH!!! No cookie.
java.lang.Exception: Stack trace
at java.lang.Thread.dumpStack(Unknown Source)
at hw3.TestHelper.verify(TestHelper.java:26)
at hw3.Homework3.main(Homework3.java:91)
smooshing [ 0 1 2 3 4 5 6 ]:
[ 0 1 2 3 4 5 6 ]
I am getting a bit closer but it is still working incorrectly so something must be wrong with my logic
Maybe you should take a look on how to work with Collections. Take a look to the Java Tutorials.
I would tackle your problem as follows:
Create a Set object
Insert the values from your array in the set (a set cannot have duplicates, so it will not allow you to insert one), and
Return the resulting set (or convert it to an array) and do whatever you need to do with it.
So, it would be something like this:
public Integer deduplicateArray(int[] values) {
Set<Integer> intSet = new HashSet<>(values.length);
for(Integer i : values) {
if(!intSet.add(i))
System.out.println("Value " + i + " is duplicated and was not added");
}
return intSet.toArray();
}
Notice that you specify that the set will contain Integer objects (not int values), because a Collection can only hold objects. You can use an Integer object as any other int value:
// ...
int aValue; // This is a int (primitive) variable
Integer someInteger = 12; // This is an Integer object
aValue = someInteger + 3; // aValue is still a `int` (primitive) variable
// ...
Some useful links:
The Set Interface (The Java Tutorials)
The HashSet API
Hope this helps
For example, you can do it as following:
int[] array = {0, 1, 0, 3, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1};
Set<Integer> set = new TreeSet<>();
for (int i : array) {
set.add(i);
}
System.out.println("set = " + set);
And the result will be:
set = [-1, 0, 1, 3]
Related
This question already has answers here:
What is a debugger and how can it help me diagnose problems?
(2 answers)
Closed 3 years ago.
I'm reviewing arrays and for loops among other things in my computer science course. One of the examples used was the code below. After being run, the array displays 2, 3, 4, 2. How is this?
int[] numbers = {1, 2, 3, 4};
for (int i = 0; i < numbers.length; i++) {
numbers[i] = numbers[(i+1) % numbers.length];
}
System.out.println(numbers);
An important concept in understanding the code you are looking it, especially the block inside the for loop, is the modulus operator (%) also known as the remainder operator. When applied, the % operator returns the remainder of two numbers.
Hence, the computation:
(i+1) % numbers.length
will always return a remainder.
Walking through it with a debugger (or print statements as suggested) while evaluating the values (and operations) at each iteration is a great way of understanding it.
You can also read more about it: https://www.baeldung.com/modulo-java
As you are doing the operation on the same array in place.
original array [1, 2, 3, 4]
when i - 0 => number [2,2,3,4] // moving index 1 item to index 0
when i - 2 => number [2,3,3,4] // moving index 2 item to index 1 from the
immediate previous array
when i - 2 => number [2,3,4,4] // moving index 3 item to index 2 from the
immediate previous array
when i - 3 => number [2,3,4,2] // moving index 0 item to index 3 from the
previous array
Keep in mind that % is modular arithmetic - it's the remainder when you divide the left-hand side by the right-hand side. For example, 2 % 4 = 2, 4 % 4 = 0, 6 % 4 = 2, and 8 % 4 = 0.
Here are the steps:
i = 0. (i + 1) % 4 = 1 % 4 = 1. Value at index 1 is 2. Array now contains {2, 2, 3, 4}.
i = 1. (i + 1) % 4 = 2 % 4 = 2. Value at index 2 is 3. Array now contains {2, 3, 3, 4}.
i = 2. (i + 1) % 4 = 3 % 4 = 3. Value at index 3 is 4. Array now contains {2, 3, 4, 4}.
i = 3. (i + 1) % 4 = 4 % 4 = 0. Value at index 0 is 2. Array now contains {2, 3, 4, 2}.
I'd encourage you to step through this with a debugger and/or use print statements to convince yourself that this is true and to understand why this is the case (doing so will help with understanding; if you're not convinced by a statement, either it's not true or there's something you don't understand or know about yet).
Your loop reassignes each index in your array with the value currently stored in the next index by doing (i+1).
Therefor on index [0] you get the value 2 which was on index [1] before. Same for second and third index. For the last one it is a little bit special since there is no next index the % numbers.length computation basically wraps the index so that for index [3] you will get the value of index [0] since (3+1)%4 = 0.
Note on index [3] you are getting value 2 and not 1 since you already changed the value on index [0] before that.
1st iteration
numbers[i] = numbers[1 % 4]; // answer is 1 so numbers[1] = 2
2nd iteration
numbers[i] = numbers[2 % 4]; // answer is 2 so numbers[2] = 3
Like this it will go until I becomes 3
Below is given array for infinite length which has natural numbers as it can be infinite length:
int[] myArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0, 1, 1, 1, 2, 1, 3 ......};
// at place of 10 it'll take 1, 0, at place of 11 it'll take 1, 1, at place of 12 it'll take 1, 2 an so on.....
index 0 = > value 0 = > number 0
index 1 = > value 1 = > number 1
index 2 = > value 2 = > number 2
index 3 = > value 3 = > number 3
index 4 = > value 4 = > number 4
index 5 = > value 5 = > number 5
index 6 = > value 6 = > number 6
index 7 = > value 7 = > number 7
index 8 = > value 8 = > number 8
index 9 = > value 9 = > number 9
index 10 = > value 1 = > number 10
index 11 = > value 0 = > number 10
index 12 = > value 1 = > number 11
index 13 = > value 1 = > number 11
index 14 = > value 1 = > number 12
index 15 = > value 2 = > number 12
....
....
....
for index 9 value should be 9, but at index 10 instead of value as 10 it should be 1 & again at index 11 value should be 0 , then at index 12 value should be 1 and so on...
Suppose for index value 10 we get a result as 1, for value 11 we get a result value as 0.
We have to write our logic to get the value by passing index value, index can be from 0 to 10000000.
We can not directly use array to get the value at specific index, we have to write logic like below:
public int getValue(int index){
int value = 0;
// logic to find the the value
return value;
}
I have tried below approach to get the result for passed index, but it works till two digits numbers i.e. 99. (till index 189). But for three digits & further we have to change the logic.
public static int myMethod(int index){
System.out.println("index : " + index);
if(index <= 9){
return index;
}
boolean even = (index % 2) == 0;
int num = 0 ;
char res = 0;
if(even){
num = index - ((index - 10) / 2);
System.out.println("num " + num);
res = new Integer(num).toString().charAt(0);
}else{
index = index -1;
num = index - ((index - 10) / 2);
System.out.println("num 22 : " + num);
res = new Integer(num).toString().charAt(1);
}
int result = new Integer(res+"");
System.out.println(result);
return result ;
}
This sequence is known as the Champernowne constant.
The basic approach is to work out how the total length of all the 1 digit, 2 digit, 3 digit numbers, etc. Once you know which digit range is appropriate, you can identify the exact number within the range, and then the exact digit within the number.
Full details of an efficient algorithm can be found in this pdf.
I'm going to say we start from 1 instead of 0 to make the below simpler (you can just subtract 1 from the index to include it).
Let's start with some analysis:
There are 9 1-digit numbers (1-9) consuming the first 9*1 = 9*100*1 = 9 positions.
There are 90 2-digit numbers (10-99) consuming the next 90*2 = 9*101*2 = 180 positions.
There are 900 3-digit numbers (100-999) consuming the next 900*3 = 9*102*3 = 2700 positions.
Etc.
As can be seen from the above, the n-digit numbers take up 9*10n-1*n positions.
From here, it's not too hard to convert an index to the corresponding number by:
Looping over each of the above cases (with a simple for loop), subtracting the corresponding number of positions from our index until doing this would give us a negative number.
Divide our index by the number of digits we're currently at to get the offset, then add the first value using that number of digits (which is a multiple of 10) to find the number we're looking for.
To determine the digit we're looking for (if not looking for the whole number), we can take the remainder of our the above division to give us our answer.
For example:
Let's say we need to get the value of index 200 (or 201, if starting from 0).
Excluding the 1-digit numbers gives us 200-9 = 191.
Excluding the 2-digit numbers gives us 191-180 = 11.
Trying to exclude the 3-digit numbers would lead to a negative number, so we know it's a 3-digit number.
Divide 11 by the number of digits (3) to give us 3 (rounded down).
The 3rd (starting from 0) 3-digit number is 100+3 = 103.
Since 11%3 = 2, we're looking for the 2nd digit (starting from 0), so 3 is our answer.
Code:
final int[] POWERS_OF_10 = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
int getValue(int index){
if (index-- == 0) // remove this if-statement to start from 1
return 0;
int digits = 0;
int positions = 0;
while (positions <= index)
{
index -= positions;
digits++;
positions = 9 * digits * POWERS_OF_10[digits-1];
}
int number = index / digits + POWERS_OF_10[digits-1];
int digit = index % digits;
int value = Integer.toString(number).charAt(digit) - '0'; // lazy approach
// int value = number / POWERS_OF_10[digits-digit-1] % 10; // non-lazy approach
return value;
}
This:
for (int i = 0; i < 20; i++)
System.out.print(getValue(i) + ", ");
Will print out:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 0, 1, 1, 1, 2, 1, 3, 1, 4,
Live demo.
This function (in JavaScript convert it yourself to Java), gives for an index x the length of the number and the position of the digit under this index.
Eg. For index 15, it wil return {length: 2, pos: 1} because under index 15 there is the 2 of 12, so the index of 2 relative to 12 is 1 and the length of 12 is 2 digits.
index: 0|1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|..
value: 0|1|2|3|4|5|6|7|8|9|1 |0 |1 |1 |1 |2 |..
I guess that you can write the code to grab the right values from the array yourself.
function find(x){
var length = 0;
while(x > 0){
length++;
x = x - (10**(length-1)) * length * 9;
}
return {length: length, pos: (x % length) + length -1};
}
console.log(find(15));
Can someone explain to my why this method works, I've worked through what it does, but why does this work. Is there a pattern that binary numbers have? Like for example at i = 3, why does it do res[1] + 1 to get 2. How does res[3 >> 1] + (3&1) help to count the number of ones in the binary number of 3?
What the code should do: It works so don't worry about that. It is supposed to return a list that contains the number of ones in the binary representation of each number until num+1. And num is always >= 0. So for num = 5, you would get [0, 1, 1, 2, 1, 2], where the last index represents the number of 1s in the binary representation of 5, and the first index is number of ones in binary rep of 0.
Code:
public int[] countBits(int num) {
int[] res = new int[num+1];
for (int i = 0; i<num+1; i++){
res[i] = res[i >> 1] + (i & 1);
}
return res;
}
This is the part I can't wrap my head around:
res[i] = res[i >> 1] + (i & 1);
EDIT - This is not homework, so please fully explain your answer. This is to help with interviews.
int[] res = new int[num+1];
for (int i = 0; i<num+1; i++){
res[i] = res[i >> 1] + (i & 1);
}
return res;
rewritten as
int[] res = new int[num+1];
for (int i = 0; i<num+1; i++){
x = res[i >> 1];
y = (i & 1);
res[i] = x + y;
}
return res;
Create an array to fit the answers, +1?
for each, starting at the low end.
res[0] = res[0] + 0&1 = 0 + 0 = 0;
res[1] = res[0] + 1&1 = 0 + 1 = 1;
res[2] = res[1] + 0&1 = 1 + 0 = 0;
res[3] = res[1] + 1&1 = 1 + 1 = 2;
Looking at this pattern, I can see that because of the right shift, and the masking with &, it's splitting the problem into 2, one that's been solved previously due to the iteration order, and a bit check of the last digit.
assuming a 8 bit int, for brevity,
1 = 00000001
2 = 00000010
3 = 00000011
Split the binary into parts.
i i>>1 y&1
1 = 0000000 1
2 = 0000001 0
3 = 0000001 1
So it fetches the results for the number of ones in the first half of the array, then counts the last digit.
Because of the iteration order, and array initialisation values, this is guaranteed to work.
For values < 0 , due to 2's compliment it gets hairy, which is why it only works for values >=0
in 'res[i] = res[i >> 1] + (i & 1);'
one number's result is divide into 2 parts
the last bit is 1 or not,which can be calculate by (i & 1).
the first (n-1) bits,this number is equals to res[i >> 1]'s bitcount.this is a simple recursive call
shift by 1 gives the floor number divided by 2.
AND 1 returns 1 if the last bit of the number is 1
Hope the below table helps to see what is happening :) Just my 2 cents.
<pre>
--------------------------------
<b>
# 8 4 2 1 >>1 &1 Ans
</b>
-------------------------------
0 0 0 0 0 0 0 0
1 0 0 0 1 0 1 1
2 0 0 1 0 1 0 1
3 0 0 1 1 1 1 2
4 0 1 0 0 2 0 1
5 0 1 0 1 2 1 2
6 0 1 1 0 3 0 2
7 0 1 1 1 3 1 3
8 1 0 0 0 4 0 1
9 1 0 0 1 4 1 2
10 1 0 1 0 5 0 2
11 1 0 1 1 5 1 3
12 1 1 0 0 6 0 2
13 1 1 0 1 6 1 3
14 1 1 1 0 7 0 3
15 1 1 1 1 7 1 4
</pre>
Here is example of my input data:
5 // Number of 1D arrays, in this case we'll have array[5][3]
1 2 3 // Values of array[i][0..2]
1 1 1
1 0 0
1 1 0
2 1 0
And output is:
12 // Maximum sum ({1 2 3} + {1 1 1} + {2 1 0} = {4 4 4} = 12) - END SUM VALUES MUST BE EQUAL(4 4 4).
3 // Number of arrays used to get this sum
The problem is to find maximum sum using n arrays, and secod condition is to use minimum number of arrays. Also if sum > 300 we stop algorithm. (300 is maximum). Here is my code, it's I get good answers but it's time complexity is O(2^n-1). I'm thinking that it's possible to save results in some way and don't calculate same things many times, but I don't know how yet.
public static int[] fuel(int start, int[] sum, int counter) {
int[] val = { sum[0] + crystal[start][0], sum[1] + crystal[start][1], sum[2] + crystal[start][2] };
int newSum = val[0] + val[1] + val[2];
if(newSum > 300)
return null;
if(val[0] == val[1] && val[1] == val[2]) { // All 3 values have to be equal!
if(newSum > result[0]) {
result[0] = newSum;
result[1] = counter;
} else if(newSum == result[0] && result[1] > counter) {
result[1] = counter;
}
}
if(start + 1 < crystalNumber) {
fuel(start + 1, val, counter + 1);
fuel(start + 1, sum, counter);
}
return result;
}
This may not be the best algorithm to solve this but it should be quicker than O(2^N).
The idea is to record all reachable sums as you loop through the input array. You can use a dictionary whose key is a unique hash of the possible sums, for the sake of simplicity let's just assume the key is a string which concatenates the three sums, for example, the sums [3,5,4] we'll use the key "003005004" , the value of the dictionary will be the minimum numbers of arrays to reach that sum.
So in your case:
1 2 3 => [001002003] =1
1 1 1 => [001001001] =1, [002003004]=2 (itself and use [001002003] from above)
1 0 0 => [001000000] =1, [002002003] =2, [002001001] =2, [003003004] =3
1 1 0 ...
2 1 0 ...
In the end, you will find [004004004] =3 and that's your answer.
This may seems going through all combinations as well so why it's quicker, it's because the maximum sum is 300 for each number, so in the very worst case, we may have 301^3 keys filled and have to update their values for each new input array. This is however still O(n) and despite of the large constant, it should still run much faster than O(2^n). (If you solve 300^3*n = 2^n, n is around 30-ish)
A simple hash function would be a*301*301+b*301+c
I think the problem is given m 1-D arrays and a number n, find the maximum sum using n arrays from m;
The solution looks straight forward. keep sum of each 1-D array in a separate array, say sum[]
1 2 3 = 6
1 1 1 = 3
1 0 0 = 1
1 1 0 = 2
2 1 0 = 3
Sort this array sum
6,3,3,2,1
and return the sum of first n elements of this array.
public class IntegerSet {
int dMax;
boolean[] set;
public IntegerSet(int domainMax) {
dMax = domainMax + 1;
set = new boolean[dMax];
}
...some methods...
public static IntegerSet union(IntegerSet s1, IntegerSet s2) {
IntegerSet union = new IntegerSet(Math.max(s1.dMax, s2.dMax));
for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {
union.set[i] = (s1.set[i] || s2.set[i]);
}
return union;
}
Can anyone tell me whats wrong with this?
I can't understand why I'm getting the error message after hours: Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6
As the two sets supplied as arguments may have different domain max; the resulting union should have whichever of these two domain max is larger hence why I am using Math.max.
Any help would be appreciated.
The problem arises when s1 and s2 have different lengths. These lines are flawed:
IntegerSet union = new IntegerSet(Math.max(s1.dMax, s2.dMax));
for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {
Think about what two sets of unequal length look like:
(using 1 and 0 in place of true and false)
s1: {0 1 0 0 1 1} length = 6
s2: {1 1 1 0 0 0 1 0 1 1 0 1} length = 12
You've programmed your loop to iterate from 0 up to the maximum length of the two sets, which in the above example is 12 (meaning that the last value your loop will use is 11). But s1 is only 6 elements long--its last valid index is 5! As the loop erroneously attempts to access elements 7 through 12 (indices 6 through 11) of s1, it throws an ArrayIndexOutOfBoundsException.
To fix this, you should use the minimum length of the two sets in both of the lines where you use the maximum. This way, you will be taking the union:
s1: {0 1 0 0 1 1} length = 6
s2: {1 1 1 0 0 0 1 0 1 1 0 1} length = 12
union: {1 1 1 0 1 1} length = min(6, 12) = 6
Instead of
s1: {0 1 0 0 1 1}! ! ! ! ! ! length = 6; no elements 7 through 12!
s2: {1 1 1 0 0 0 1 0 1 1 0 1} length = 12
union: {1 1 1 0 1 1 ! ! ! ! ! !} length = max(6, 12) = 12 -> errors
This leaves the later section of s2 out of the union, as there are no corresponding elements in s1 to perform a boolean || with. However, you could also do something like this:
IntegerSet union = new IntegerSet(Math.max(s1.dMax, s2.dMax));
for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {
if (s2.set.length > s1.set.length)
{
union.set[i] = s2.set[i] || (i < s1.set.length ? s1.set[i] : false);
}
else
{
union.set[i] = s1.set[i] || (i < s2.set.length ? s2.set[i] : false);
}
}
This will use false's for every missing element in the shorter set, resulting in the union being:
s1: {0 1 0 0 1 1} length = 6
s2: {1 1 1 0 0 0 1 0 1 1 0 1} length = 12
union: {1 1 1 0 1 1 1 0 1 1 0 1} length = max(6, 12) = 12
All entries are simply copied from the longer set, since anything || false is itself.
This:
dMax = domainMax + 1;
should be:
dMax = domainMax;
Or just use set.length.
Your for-loop goes from 0 to the max size of s1 and s2. But because (in the situation that throws errors), one of your IntegerSets is smaller, the for-loop goes past the size of the smaller IntegerSet when retrieving all of the booleans from the larger IntegerSet
for (int i = 0; i < (Math.max(s1.dMax, s2.dMax)); i++) {
union.set[i] = (s1.set[i] || s2.set[i]);
}
If the size of one set is smaller than the max, then you are going to get an IndexOutOfBoundsException.
Example:
Say you have the following conditions:
s1 = {0, 1, 1, 0, 1}
s2 = {0, 0, 0}
s1.dMax = 5, so s1.set has a size of 5
s2.dMax = 3, so s2.set has a size of 3
In your for-loop, you are going to iterate from 0 to 4. When the following occurs:
i = 3
s1.set[i] = s1.set[3] //IndexOutOfBoundsException because the size of s1.set is 3.
You have a couple options of how you can fix this:
You can add a check in your for-loop to ensure that you aren't
going to get an IndexOutOfBoundsException for your smaller
IntegerSet and just set the index in union to the boolean value of your larger set.
You can pad to your smaller IntegerSet depending on what you want the
union to be for the blank indicies.
Use the min size of the two IntegerSets if you want to ignore the
extra booleans (Judging from the fact that you made the union set
the size of the max, I am guess that is not the case)
Side Note: You also do not need to add the +1 to the dMax variable when you create your union IntegerSet. That is going to result in your having an extra index that you don't need and could cause problems later.
You are using dMax as the number of boolean array elements in one place, and as the domain maximum (wrong) when you create the new union set. (That causes you to make union 1 element too large.)
Several things to consider when you rewrite your code:
Assuming domainMax implies a set of integers from [0, domainMax], do define a boolean array with domainMax+1 elements (don't bother with a dMax variable, you can get that info by checking set.length
In the "union" function, be sure to handle the case where one or both of the input IntegerSets is null
Use protected set to make sure the internal representation of the IntegerSet is not known or accessed outside your class
When you perform the union of two non-null IntegerSets, only perform the or operation (||) for the case where both sets have values; then for the "bigger" set, simply copy over the remaining items.