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
Related
A non-empty array A consisting of N integers is given.
A peak is an array element which is larger than its neighbors. More precisely, it is an index P such that 0 < P < N − 1, A[P − 1] < A[P] and A[P] > A[P + 1].
For example, the following array A:
A[0] = 1
A[1] = 2
A[2] = 3
A[3] = 4
A[4] = 3
A[5] = 4
A[6] = 1
A[7] = 2
A[8] = 3
A[9] = 4
A[10] = 6
A[11] = 2
has exactly three peaks: 3, 5, 10.
We want to divide this array into blocks containing the same number of elements. More precisely, we want to choose a number K that will yield the following blocks:
A[0], A1, ..., A[K − 1],
A[K], A[K + 1], ..., A[2K − 1],
...
A[N − K], A[N − K + 1], ..., A[N − 1].
What's more, every block should contain at least one peak. Notice that extreme elements of the blocks (for example A[K − 1] or A[K]) can also be peaks, but only if they have both neighbors (including one in an adjacent blocks).
The goal is to find the maximum number of blocks into which the array A can be divided.
Array A can be divided into blocks as follows:
one block (1, 2, 3, 4, 3, 4, 1, 2, 3, 4, 6, 2). This block contains three peaks.
two blocks (1, 2, 3, 4, 3, 4) and (1, 2, 3, 4, 6, 2). Every block has a peak.
three blocks (1, 2, 3, 4), (3, 4, 1, 2), (3, 4, 6, 2). Every block has a peak. Notice in particular that the first block (1, 2, 3, 4) has a peak at A[3], because A[2] < A[3] > A[4], even though A[4] is in the adjacent block.
However, array A cannot be divided into four blocks, (1, 2, 3), (4, 3, 4), (1, 2, 3) and (4, 6, 2), because the (1, 2, 3) blocks do not contain a peak. Notice in particular that the (4, 3, 4) block contains two peaks: A[3] and A[5].
The maximum number of blocks that array A can be divided into is three.
Write a function:
class Solution { public int solution(int[] A); }
that, given a non-empty array A consisting of N integers, returns the maximum number of blocks into which A can be divided.
If A cannot be divided into some number of blocks, the function should return 0.
For example, given:
A[0] = 1
A[1] = 2
A[2] = 3
A[3] = 4
A[4] = 3
A[5] = 4
A[6] = 1
A[7] = 2
A[8] = 3
A[9] = 4
A[10] = 6
A[11] = 2
the function should return 3, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [0..1,000,000,000].
My Understanding of the problem :
Each sub array should contain at least one peak
An element which forms a peak can be in an Adjacent sub array.
Return max possible sub arrays
My Question
Consider Main Array : [0,1,0,1,0]
Possible sub arrays as per understanding : [0,1] [0,1,0]
Each subarray has a peak.
Subarray 1 [0,1] has peak element shared with adjacent array [0,1,0].
Subarray 2 [0,1,0] contains peak 0<1>0.
So max possible sub arrays are 2 but a test case in Codility returns max possible sub arrays as 1.
Below is my code
// you can also use imports, for example:
import java.util.*;
// you can write to stdout for debugging purposes, e.g.
// System.out.println("this is a debug message");
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int count=0,size=A.length;
if(size<2)
return 0;
System.out.println(Arrays.toString(A));
for(int i=1;i<size-1;i++){
if(A[i-1]<A[i] && A[i]>A[i+1]){
count++;
i++;
}
}
return count;
}
}
Test case which failed in Codility click here
I believe there is a gap in my understanding. Any help would be helpful :)
https://app.codility.com/demo/results/training5KP2PK-P4M/
https://github.com/niall-oc/things/blob/master/codility/peaks.py
Breaking an array into even parts is another way of factorizing the length of the array.
Array of length 12
[0,1,0,1,0,0,0,1,0,0,1,0,]
Factors of 12.
The square root of 12 is 3.464... so start with 3 and irterate down to 1 and divide each number into 12. This gives you a set of numbers {1, 2, 3, 4, 6, 12}.
Process
Because of how a peak is defined you cannot have 12 peaks in this array so remove 12 from the set. Starting d as the largest number divide the array int d parts. And check each part has a peak, if so then d is the maximum number of equal parts to all contain at least one peak. If not so then iterate to the next largest divisor and try that until you find a solution.
First of all you need to be congratulated to write a concise program to calculate the number of peaks. But the question is not to count the peaks.
It is to find the number of equal sized array and each having at least one peak. And a peak cannot be the first or last element as stated in the problem 0 < P < N − 1
Now quoting your question:
Consider Main Array : [0,1,0,1,0]
Possible sub arrays as per understanding : [0,1] [0,1,0] Each subarray has a peak. Subarray 1 [0,1] has peak element shared with adjacent array [0,1,0]. Subarray 2 [0,1,0] contains peak 0<1>0.
So max possible sub arrays are 2 but a test case in Codility returns max possible sub arrays as 1.
I see below issues:
your sub array sizes are not equal
array [0,1] does not have a peak
So, the array cannot be divided in equal parts each having a peak and hence only one array remains [0,1,0,1,0].
I saw this code to shuffle a list:
public static void shuffle(List<Integer> numbers) {
if(numbers == null || numbers.isEmpty()) return;
for(int i = 0; i < numbers.size(); ++i) {
int index = (int) (i + Math.random()*(numbers.size() - i));
swap(numbers, i, index);
}
}
The code seem to work but I don't understand this snippet:
int index = (int) (i + Math.random()*(numbers.size() - i));
Basically it is i + R*(n-i) but how does this ensure that: i) we won't get an out of bounds index or ii) I won't be changing the same element's i.e. index == i and the shuffle would not be that random?
Math.random() returns a uniform random number in the interval [0, 1), and numbers.size() - i, ideally, scales that number to the interval [0, numbers.size() - i). For example, if i is 2 and the size of the list is 5, a random number in the interval [0, 3) is chosen this way, in the ideal case. Finally, i is added to the number and the (int) cast discards the number's fractional part. Thus, in this example, a random integer in [2, 5) (that is, either 2, 3, or 4) is generated at random, so that at each iteration, the number at index X swaps with itself or a number that follows it.
However, there is an important subtlety here. Due to the nature of floating-point numbers and rounding error when scaling the number, in extremely rare cases the output of Math.random()*(numbers.size() - i) might be equal to numbers.size() - i, even if Math.random() outputs a number that excludes 1. rounding error can cause the idiom Math.random()*(numbers.size() - i) to bias some results over others. For example, this happens whenever 2^53 is not divisible by numbers.size() - i, since Math.random() uses java.util.Random under the hood, and its algorithm generates numbers with 53 bits of precision. Because of this, Math.random() is not the best way to write this code, and the code could have used a method specially made for generating random integers instead (such as the nextInt method of java.util.Random). See also this question and this question.
EDIT: As it turns out, the Math.random() * integer idiom does not produce the issue that it may return integer, at least when integer is any positive int and the round-to-nearest rounding mode is used as in Java. See this question.
Math.random() always returns a floating-point number between 0 (inclusive) and 1 (exclusive). So when you do Math.random()*(numbers.size() - i), the result will always be between 0 (inclusive) and n-i (exclusive).
Then you add i to it in i + Math.random()*(numbers.size() - i).
Now the result, as you can see, will be between i (inclusive) and n (exclusive).
After that, you are casting it to an int. When you cast a double to an int, you truncate it, so now the value of index will somewhere from ``iton - 1``` (inclusive for both).
Therefore, you will not have an ArrayIndexOutOfBoundsException, since it will always be at least 1 less than the size of the array.
However, the value of index could be equal to i, so yes, you are right in that a number could be swapped with itself and stay right there. That's perfectly fine.
You have a list of 1 to 50 ints.
So get a random value from 0 to 49 inclusive to index it.
say it is 30.
Get item at index 30.
Now replace item at index 30 with item at index 49.
Next time generate a number between 0 and 48 inclusive. 49 will never be reached and the number that was there occupies the slot of the last number used.
Continue this process until you've exhausted the list.
Note: that the expression (int)(Math.random() * n) will generate a random number between 0 and n-1 inclusive because Math.random generates a number between 0 and 1 exclusive.
Instead of using such a custom method, I recommend you use OOTB Collections.shuffle. Check this to understand the logic implemented for Collections.shuffle.
Analysis of your code:
Math.random() returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Now, let's assume numbers.size() = 5 and dry run the for loop:
When i = 0, index = (int) (0 + Math.random()*(5 - 0)) = (int) (0 + 4.x) = 4
When i = 1, index = (int) (1 + Math.random()*(5 - 1)) = (int) (1 + 3.x) = 4
When i = 2, index = (int) (2 + Math.random()*(5 - 2)) = (int) (2 + 2.x) = 4
When i = 3, index = (int) (3 + Math.random()*(5 - 3)) = (int) (3 + 1.x) = 4
When i = 4, index = (int) (4 + Math.random()*(5 - 4)) = (int) (4 + 0.x) = 4
As you can see, the value of index will remain 4 in each iteration when numbers.size() = 5.
Your queries:
how does this ensure that: i) we won't get an out of bounds index
As already explained above using the dry run, it will never go out of bounds.
or ii) I won't be changing the same element's i.e. index == i and the
shuffle would not be that random?
swap(numbers, i, index); is swapping the element at index, i with the element at index, 4 each time when numbers.size() = 5. This is illustrated with the following example:
Let's say numbers = [1, 2, 3, 4, 5]
When i = 0, numbers will become [5, 2, 3, 4, 1]
When i = 1, numbers will become [5, 1, 3, 4, 2]
When i = 2, numbers will become [5, 1, 2, 4, 3]
When i = 3, numbers will become [5, 1, 2, 3, 4]
When i = 4, numbers will become [5, 1, 2, 3, 4]
int index = (int) (i + Math.random()*(numbers.size() - i)); - it is important to note that Math.random() will generate a number which belongs to <0;1). So it will never exceed the boundry as exclusive max will be: i + 1*(number.size() -i) = number.size
This point is valid, it can happen.
I was trying to solve a problem from the Codility with a given solution. The problem is provided below:
You are given N counters, initially set to 0, and you have two possible operations on them:
increase(X) − counter X is increased by 1,
max counter − all counters are set to the maximum value of any counter.
A non-empty array A of M integers is given. This array represents consecutive operations:
if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
if A[K] = N + 1 then operation K is max counter.
For example, given integer N = 5 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the values of the counters after each consecutive operation will be:
(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)
The goal is to calculate the value of every counter after all operations.
Write a function:
class Solution { public int[] solution(int N, int[] A); }
that, given an integer N and a non-empty array A consisting of M integers, returns a sequence of integers representing the values of the counters.
The sequence should be returned as:
a structure Results (in C), or
a vector of integers (in C++), or
a record Results (in Pascal), or
an array of integers (in any other programming language).
For example, given:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the function should return [3, 2, 2, 4, 2], as explained above.
Assume that:
N and M are integers within the range [1..100,000];
each element of array A is an integer within the range [1..N + 1].
Complexity:
expected worst-case time complexity is O(N+M);
expected worst-case space complexity is O(N) (not counting the storage required for input arguments).
I have a solution provided,
public static int[] solution(int N, int[] A) {
int[] counters = new int[N];
int currMax = 0;
int currMin = 0;
for (int i = 0; i < A.length; i++) {
if (A[i] <= N) {
counters[A[i] - 1] = Math.max(currMin, counters[A[i] - 1]);
counters[A[i] - 1]++;
currMax = Math.max(currMax, counters[A[i] - 1]);
} else if (A[i] == N + 1) {
currMin = currMax;
}
}
for (int i = 0; i < counters.length; i++) {
counters[i] = Math.max(counters[i], currMin);
}
return counters;
}
It seems they use 2 storage to hold and update the min/max values and use them inside the algorithm. Obviously, there is a more direct way to solve the problem ie. increase the value by 1 or set all the values to max as suggested and I can do that. The drawback will be to lower perfromance and increased time complexity.
However, I would like to understand what is going on here. I spend times debugging with the example array but the algorithm is still little confusing.
Anyone understand it and can explain to me briefly?
It is quite simple, they do lazy update. You keep track at all times of what is the value of the counter that has the highest value (currMax). Then, when you get a command to increase all counters to that maxValue, as that is too expensive, you just save that the last time you had to increase all counters to maxValue, that value was currMin.
So, when do you update a counter value to that value? You do it lazily, you just update it when you get a command to update that counter (increase it). So when you need to increase a counter, you update the counter to the max between its old value and currMin. If this was the first update on this counter since a N + 1 command, the correct value it should have is actually currMin, and that will be higher (or equal) to its old value. One you updated it, you add 1 to it. If now another increase happens, currMin doesn't actually matter, as the max will take its old value until another N + 1 command happens.
The second for is to account for counters that did not get an increase command after the last N + 1 command.
Note that there can be any number of N + 1 commands between 2 increase operations on a counter. It still follows that the value it should have is the maxValue at the time of the last N + 1 command, it doesn't really matter that we didn't update it before with the other maxValue from a previous N + 1, we only care about latest.
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.
I have an array of numbers nums[] and target such that it satisfies the below condition
{{nums[],target}
1> {{8, 2, 2, 1},12} --> returns true
2> {{8, 2, 2, 1},9} --> returns true
1 condition> identical adjacent values with a subset of remaining numbers sum to target (or)
2 condition> identical adjacent values are not chosen such that subset of other numbers sum to target.
so that in this example
1> 8+2+2 = 12.
2> 8+1=9.
how do i handle the above 2 conditions in Java.
EDITED FOR DANTE:
Expected This Run
groupSumClump(0, {2, 4, 8}, 10) → true true OK
groupSumClump(0, {1, 2, 4, 8, 1}, 14) → true true OK
groupSumClump(0, {2, 4, 4, 8}, 14) → false false OK
groupSumClump(0, {8, 2, 2, 1}, 9) → true false X
groupSumClump(0, {8, 2, 2, 1}, 11) → false false OK
groupSumClump(0, {1}, 1) → true false X
groupSumClump(0, {9}, 1) → false false OK
other tests false X
*Code for Dante:
http://www.ideone.com/xz7ll
#Dante,Please check the above link,it fails for test scenarios mentioned.
I've seen you struggling with this question for a long time, so, here are some codes....
EDITed
int nums_another[] = new int [nums.length];
int i = 0;
int j = 0;
i++;
int c = 1;
while (i < nums.length){
if (nums[i] == nums[i-1]) { // count identical numbers
c++;
}
else { // not identical, store sum of previous identical numbers (possibly only 1 number)
if (nums[i-1] != 0) {
nums_another[j] = nums[i-1] * c;
j++;
}
c = 1;
}
i++;
}
if (nums[i-1] != 0) { // store last
nums_another [j] = nums[i-1] * c;
}
Now nums_another includes:
the sums of the groups of the adjacent identical numbers (in your case 4 = 2 + 2)
not identical numbers (in your case 8, 1)
0's at last (thus in all 8 4 1 0)
By the way, the problem with your code is that:
because you set the next identical number to 0 immediately, it will fail for 3 or more,
for example, 8 2 2 2 1 -> 8 4 0 2 1 instead of -> 8 6 0 0 1
You can solve both conditions simultaneously with two local variable: a set of 'lonely' numbers and an accumulator for 'adjacent' values:
Step through the array.
For each value, check the previous value (if there is one) and the next value (if there is one).
If one of them is identical to the current value, increment the 'adjacent' accumulator, otherwise add the value to the 'lonely numbers' set.
To check condition 2, subtract the value of the 'adjacent' accumulator from the target, for condition 1 leave it unchanged.
The rest of the problem is to determine whether some subset of the values in the 'lonely set' sums to the target value. This is a well-known numerical problem which is expensive to compute (exponential effort), but not difficult to program. You can find many solutions if you search for its name: it's called the 'knapsack problem'.