Manual array copy in a nested for loop - java

I trying to find all 2s, move them to the back of the array, and turn them into 0s without loosing the order of the array. For example, [1,2,3,2,2,4,5] would become [1,3,4,5,0,0,0]. My code works fine but the IDE is telling me that the nested for loop is copying the array manually and wants me to replace it with System.arraycopy(). How would I go about that?
Code looks like this:
int[] numbers = {1,2,3,2,2,4,5};
for (int i = 0; i < numbers.length; i++){
if (numbers[i] == 2){
for (int j = i; j < numbers.length - 1; j++){
numbers[j] = numbers[j + 1];
}
numbers[numbers.length-1] = 0;
i --;
}
}

The following statement:
for (int j = i; j < numbers.length - 1; j++){
numbers[j] = numbers[j + 1];
}
Can be replaced by:
System.arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i);
IDEs like IntelliJ should suggest that automatically when you press alt + enter (default key combination).
Now about arraycopy()
From the documentation, java.lang.System.arraycopy() will copy n elements (last argument) from the source array (1st argument) to the destination array (3rd argument) with the corresponding indexes to start from (2nd and 4th arguments).
More specifically, when calling arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i) the arguments are:
numbers: The source array.
i + 1: The starting position in the source array.
numbers: The destination array.
i: The starting position in the destination data.
numbers.length - 1 - i: The number of array elements to be copied.
In your case, elements will be copied from your array, to itself, but the fact that source starting position is shifted from the destination starting position will induce the global shifting you're after (moving elements to the left).
About the number of elements to be moved, it should move i elements minus the first one that doesn't move and only gets overwritten. Hence the length - 1 - i.

The inner loop could be replaced with an arraycopy, however, you don't need an inner loop:
int[] numbers = {1,2,3,2,2,4,5};
int j = 0;
for (int i = 0; i < numbers.length; i++){
if (numbers[i] != 2){
numbers[j++] = numbers[i];
}
}
while (j < numbers.length) {
numbers[j++] = 0;
}
UPDATE
Or even:
int[] numbers = {1,2,3,2,2,4,5};
int j = 0;
for (int n: numbers){
if (n != 2){
numbers[j++] = n;
}
}
Arrays.fill(numbers,j,numbers.length,0);

The key thing is pretty simple: if you can reduce the lines of code you are responsible for (for example by using utility methods such as Arrays.arraycopy()) - then do that.
Keep in mind: each line that you write today, you have to read and understand tomorrow, and to probably modify in 5 weeks or months from now.
But then: I think you are over-complicating things here. I would use a temporary list, like this:
List<Integer> notTwos = new ArrayList<>();
int numberOfTwos = 0;
for (int i=0; i<source.length; i++) {
if (source[i] == 2) {
numberOfTwos++;
} else {
notTwo.append(source[i]);
}
}
... simply append `numberOfTwo` 0s to the list, and then turn it into an array
You see: you are nesting two for-loops, and you are repeatedly copying around elements. That is inefficient, hard to understand, and no matter how you do it: way too complicated. As shown: using a second list/array it is possible to "solve" this problem in a single pass.

After replacing your inner loop with System.arrayCopy the code should look like:
int[] numbers = { 1, 2, 3, 2, 2, 4, 5 };
for (int i = 0; i < numbers.length; i++) {
if (numbers[i] == 2) {
System.arraycopy(numbers, i + 1, numbers, i, numbers.length - 1 - i);
numbers[numbers.length - 1] = 0;
i--;
}
}

Related

How can I create a java program to find the amount of consecutive numbers in an array?

I'm trying to make a Java program to find the number of consecutive numbers in an array. For example, if an array has the values, 1,8,10,4,2,3 there are 4 numbers that are consecutive (1,2,3,4). I've created this program, but I'm getting an error on lines 28 and 31 for ArrayIndexOutOfBoundsException, how do I fix the error? (I'm not even sure if the program I made will work if the errors are fixed). Note: I know there are many solutions online for this but I'm a beginner programmer, and I'm trying to do this a more simple way.
import java.util.Arrays;
class Main {
public static void main(String[] args) {
consec();
}
static void consec()
{
int[] nums = {16, 4, 5, 200, 6, 7, 70, 8};
int counter=0;
Arrays.sort(nums);
for (int i=0; i < nums.length; i++)
if (i != nums.length - 1)
System.out.print(nums[i] + ", ");
else
System.out.print(nums[i]);
for (int i=0; i < nums.length; i++)
for (int j=i; j < nums.length - i; j++)
if (nums[j + 1] - 1 == nums[j])
counter++;
else if (nums[j+1]==counter)
System.out.print("Consective amount is" + counter);
}
}
The issue for the exception lies within the access of nums[j + 1].
Note that j can be as large as nums.length - 1 due to the for loop.
Thus j + 1 can be nums.length which is an OutOfBounds array index.
Secondly I don't think your code solves the task - for example you only print a result if the number of consecutive numbers you've counted appears within the array. However I don't see how these things should correlate.
You can solve the problem like this:
for (int i = 1; i < nums.length; i++) {
if (nums[i-1] == nums[i] - 1) {
counter+= 2;
int j = i + 1;
while (j < nums.length && nums[j] - 1 == nums[j-1]) {
j++;
counter++;
}
i = j;
}
}
System.out.print("Consective amount is" + counter);
Note that the index i starts at 1, thus we can be assured that nums[i-1] exists.
If nums has only one element we should not run into any issues as the condition i < nums.length would not be fulfilled. We count two consequitves for every start of a sequence and one addition element for every following consequtive (while loop).
When the sequence ends we try finding a new sequence behind it by moving the index i to the end of the last sequence (j = i).
The above code will sum multiple distinct sequences of consequtive numbers. For example the array [17,2,20,18,4,3] has five consequitve numbers (2,3,4 and 17,18)
The algorithm has a time colpexity within O(n) as we either increase i or j by at least on and skip i to j after each sequence.
I would recommend re-thinking your approach to scanning over the array. Ideally you should only require one for-loop for this problem.
I personally created a HashSet of Numbers, which cannot hold duplicates. From there, you can iterate from 1 to nums.length-1, and check if nums[i] - 1 == nums[i-1] (ie: if they're consecutive). If they are equal, you can add both numbers to the HashSet.
Finally, you actually have the set of consecutive numbers, but for this question, you can simply return the size of the set.
I strongly recommend you attempt this problem and follow my explanation. If you simply require the code, this is the method that I came up with.
public static int countConsecutive(int[] nums) {
Set<Integer> consecutive = new HashSet<>();
if (nums.length <= 1)
return 0;
Arrays.sort(nums);
for (int i = 1; i < nums.length; i++) {
if (nums[i] != nums[i - 1] + 1)
continue;
consecutive.add(nums[i]);
consecutive.add(nums[i - 1]);
}
return consecutive.size();
}
Here is another approach where sorting is not necessary. It uses a BitSet. And as in your example, is presumes positive numbers (BitSet doesn't permit setting negative positions).
int[] values = {4, 3, 10, 11, 6, 1, 4, 8, 7};
set the corresponding bit positions based on the values.
BitSet bits = new BitSet();
for (int i : values) {
bits.set(i);
}
Initialize some values for output, starting bit position, and the set length.
BitSet out = new BitSet();
int start = 0;
int len = bits.length();
Now iterate over the bit set finding the range of bits which occupy adjacent positions. Those will represent the consecutive sequences generated when populating the original BitSet. Only sequences of two or more are displayed.
while (start < len) {
start = bits.nextSetBit(start);
int end = bits.nextClearBit(start+1);
if (start != end-1) {
// populate the subset for output.
out.set(start,end);
System.out.println(out);
}
out.clear();
start = end;
}
prints
{3, 4}
{6, 7, 8}
{10, 11}
If you just want the largest count, independent of the actual values, it's even simpler. Just use this in place of the above after initializing the bit set.
int len = bits.length();
int total = 0;
while (start < len) {
start = bits.nextSetBit(start);
int end = bits.nextClearBit(start + 1);
if (end - start > 1) {
total += end - start;
}
start = end;
}
System.out.println(total);

selection sort loop questions in Java

I have a basic question about the inner loop length in Java selection sort. Here is the commonly used code for selection sort:
package com.java2novice.algos;
public class MySelectionSort {
public static int[] doSelectionSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
int index = i;
for (int j = i + 1; j < arr.length; j++)
/* why not the length is not arr.length-1? I think the length is
exactly the same as what it is, the array's length is a
static number as array.length-1, but when it comes to the inner
loop why it plus 1 to the array length? */
if (arr[j] < arr[index])
index = j;
int smallerNumber = arr[index];
arr[index] = arr[i];
arr[i] = smallerNumber;
}
return arr;
}
}
Imagine you're trying to sort five items. The array length is 5, which means the indexes are 0 through 4.
In the first iteration of the inner loop, you have i=0 and j=1. You need j to index to the end of the array. That's why the expression in the inner loop is j < array.Length.
i, of course, only goes from 0 to 3, which is why the outer loop has i < array.Length - 1.
If you lay five playing cards on a table and walk through the steps of the selection sort, you'll get a better idea of what's happening here.
the first loop does not need to check the last index, therefore, it goes to arr.length - 1. on the second loop, of course, the last index of the array must be checked so the loop goes to the last index (arr.length).
imagine if the first loop goes to the last index. then this line for (int j = i + 1; j < arr.length; j++) will never execute.
check out this Pseudo code of selection sort for a better understanding of the algorithm

How to traverse an array like a sine-wave?

Assume I had a 2D integer array, mxn.
I want to traverse this array like a sine wave.
In specific, traversal would start from the last row, and the first column, move onto the first row and the second column, move onto the last row and the third column.
I have attached an image to elaborate further.
t:
I only know how to traverse in order, but I was thinking of transposing the columns, changing the starting index of the column at every round, but I couldn't create a consisting loop to do so.
My attempt:
boolean startsAtbottom=true;
//cols become rows, startPoint alternates
for(int i = 0;i<n;i++)
{
if(startsAtbottom)
{
for(int j =m-1;j>-1;j--)
{
System.out.print(myArr[j][i]);
}
startsAtbottom=false;
}
else
{
for(int j =0;j<m;j++)
{
System.out.print(myArr[j][i]);
}
startsAtbottom=true;
}
}
The following code will do what you want. All you want is to change the way you traverse in consecutive iterations.
boolean traverseInOrder=true;
for(int i=0;i<columnCount;i++){
for(int j=0;j<rowCount;j++){
index=j;
if(!traverseInOrder){
index=rowCount-j-1;
}
//access the element
int element=array[i][index];
}
traverseInOrder= !traverseInOrder;
}
Your solution works, and there's nothing wrong with it. However you can get rid of the if by doing this:
for (int i = 0; i < n; i++) {
boolean goingUp = i % 2 == 0;
for (int j = 0; j < m; j++) {
int row = goingUp ? m - 1 - j : j;
System.out.println(myArr[row][i]);
}
}
Starting from your input you have that:
the outer loop index just increments from 0
the inner loop index increments for even columns and decrements for odd columns
you can determine if a number is even or odd by just checking if modulo is 0 (or by checking if (i & 0x01) == 0 but that's irrelevant)
Given this it's quite easy to model that pattern:
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
int value = data[i][i % 2 == 0 ? (cols - j - 1) : j]
}
}
The formula cols - j - 1 allows you to start from the end and go backward (see that with j = 0 you have cols - 1 and with j = cols - 1 you have cols - (cols - 1) - 1 == 0).
Mind that Java is nor column major nor row major, since a bidimensional array is just an array of arrays so according to your real layout you may need to swap indices.

Java loops,how to increment by different values?

I have an array, and I'd like to go through it with a for loop in the following way:use 2 element then skip 2 elements,then use 2 elements etc.
So for instance if I have and int array : 1 2 3 4 5 6 7 8 9 10
I'd like to work with 1 and 2 then skip 3 and 4 ,then again work with 5,6 skip 7,8 etc.
Is this possible in java?
You can do something like this:
for (int i = 0; i < array.length - 1; i += 4) {
// work with i and (i + 1)
}
Yes, you need a loop, but two would be simpler.
for (int i = 0; i < N; i += 4)
for (int j = i; j < i + 1; j++)
System.out.println(j);
Also you can do
IntStream.range(0, N)
.flatMap(i -> IntStream.range(i+1, i+3))
.forEach(System.out::println):
Something along the lines of this pseudo code will do the job:
for (int i=0; i<array.length-3; i+=4) {
int first = array[i];
int second = array[i+1];
//int third = array[i+2]; //skip this
//int fourth = array[i+3]; //skip this
}
Note: normally when looping through an array you can just use i<array.length-1, but because you could be skipping 2 at that point I believe you want to decrease the "OK" length of the array by 2 more.
Update: actual working Java code using a toggle:
boolean skip = false;
for (int i=0; i<test.length-1; i+=2) {
if (!skip) {
System.out.println(test[i]);
System.out.println(test[i+1]);
}
//int third = array[i+2]; //skip this
//int fourth = array[i+3]; //skip this
skip = !skip;
}
You can introduce as many variables as you need inside of a for loop and iterate through those. It's similar to using two loops with the advantage being that there's no extra iterations being done.
The main thing here is that you're skipping four entries in your array every time. This applies to both variables, and you also want to be sure that both of them are less than the length of the overall array (so you don't step off of it by mistake).
for (int i = 0, j = i + 1; i < array.length && j < array.length; i += 4, j += 4) {
System.out.printf("(%d, %d) ", array[i], array[j]);
}

Adding elements to last array position

Im trying to add an element to an array at its last position in Java, but I am not able to...
Or rather, I don't know how to. This is the code at the moment:
String[] values = split(line, ",");
int[][] coordinates = new int[2][values/2];
for(int i = 0; i < values.length; i++) {
if(i % 2 == 0) { //THIS IS EVEN VALUES AND 0
coordinates[0][coordinates[0].length] = values[i];
} else { //THIS IS ODD VALUE
coordinates[1][coordinates[1].length] = values[i];
}
}
EDITED VERSION:
String[] values = split(line, ",");
int[][] coordinates = new int[2][values/2];
int x_pos = 0;
int y_post = 0;
for(int i = 0; i < values.length; i++) {
if(i % 2 == 0) { //THIS IS EVEN VALUES AND 0
coordinates[0][x_pos] = values[i];
x_pos++;
} else { //THIS IS ODD VALUE
coordinates[1][y_pos] = values[i];
y_pos++;
}
}
values is being read from a CSV file. My code is I believe wrong, since it will try to add the values always at the maximum array size for coordinates[] in both cases.
How would I go around adding them at the last set position?
Thanks!
/e: Would the EDITED VERSION be correct?
Your original code has two problems:
it addresses the array badly, the las element in a Java array is at position length-1, and this would result in an ArrayOutOfBoundsException
even if you'd correct it by subtracting 1, you would always overwrite the last element only, as the length of a Java array is not related to how many elements it contains, but how many elements it was initialised to contain.
Instead of:
coordinates[0][coordinates[0].length] = values[i];
You could use:
coordinates[0][(int)Math.round(i/2.0)] = values[i];
(and of course, same with coordinates[1]...)
EDIT
This is ugly of course:
(int)Math.round(i/2.0)
but the solution I'd use is far less easy to understand:
i>>1
This is a right shift operator, exactly the kind of thing needed here, and is quicker than every other approach...
Conclusion: this is to be used in a live scenario:
Use
coordinates[0][i>>1] = values[i];
EDIT2
One learns new things every day...
This is just as good, maybe a bit slower.
coordinates[0][i/2] = values[i];
If you know you'll definitely have an even number of values you can do
for(int i = 0; i < values.length / 2; i++) {
coordinates[0][i] = values[2*i];
coordinates[1][i] = values[2*i + 1];
}
You have to store the last position somewhere. .length gives you the size of the array.
The position in the array will always be the half of i (since you put half of the elements in one array and the other half in the other).
String[] values = split(line, ",");
int[][] coordinates = new int[2][values/2];
for(int i = 0; i < values.length; i++) {
if(i % 2 == 0) { //THIS IS EVEN VALUES AND 0
coordinates[0][ i / 2] = values[i];
} else { //THIS IS ODD VALUE
coordinates[1][ i / 2 + 1 ] = values[i];
}
}
The array index for java is from "0" to "array length - 1".
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
Each item in an array is called an element, and each element is accessed by its numerical index. As shown in the above illustration, numbering begins with 0. The 9th element, for example, would therefore be accessed at index 8.
why not:
String[] values = split(line, ",");
int[][] coordinates = new int[2][values/2];
for(int i = 0; i < values.length; i+=2) {
coordinates[0][i/2] = values[i];
coordinates[1][i/2] = values[i+1];
}

Categories

Resources