Method that takes an array and compacts it down - java

The assignment given was, write a program that reads numbers off of a file, construct an array from those numbers, and move all the zeroes to the end of the array.
For example.
Before: 0, 9, 7, 0, 0, 23, 4, 0
After: 9, 7, 23, 4, 0, 0, 0, 0
After toying with it for about 2 hours i came up with this.
import java.io.*;
import java.util.Scanner;
public class Compactor{
Scanner in;
private int numNum = 0;
public void calcNumNum(){
try{
in = new Scanner(new File("compact.txt"));
while(in.hasNext()){
int dumpVal = in.nextInt();
numNum++;
}
makeArray(numNum);
}catch(IOException i){
System.out.println("Error: " + i.getMessage());
}
}
private void makeArray(int x){
int i = 0;
int[] arrayName = new int[x];
try{
in = new Scanner(new File("compact.txt"));
while(i < x){
arrayName[i] = in.nextInt();
i++;
}
compact(arrayName);
}catch(IOException e){
System.out.println("Error: " + e.getMessage());
}
}
private void compact(int[] x){
int counter = 0;
int bCounter = (x.length - 1);
for(int j = 0; j < x.length; j++){
if(x[j]!=0){
x[counter] = x[j];
counter++;
}else{
x[bCounter] = x[j];
bCounter--;
}
}
printArray(x);
}
private void printArray(int[] m){
int count = 0;
while(count < m.length){
System.out.print(m[count] + " ");
count++;
}
}
}
The file that was given to us was: 0, 6, 13, 0, 0, 75, 33, 0, 0, 0, 4, 2,9 21, 0, 86, 0, 32, 66, 0, 0.
What i got was: 6, 13, 75, 33, 4, 29, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0. (without the commas of course, i just put those in for easier reading.)
Could anyone perhaps give me insight on how to fix this problem, or maybe i should just start my code over with a different approach, the whole,
if(x[j]!=0){
x[counter] = x[j];
counter++;
}else{
x[bCounter] = x[j];
bCounter--;
}
i just made it up on the fly, thinking it would work fine, obviously it kept on going after it got past the last value and kept setting more and more values counting backwards as zeroes, no idea how to make it work though, any help would be greatly appreciated.

You're almost there with compact():
private void compact(int[] x) {
int counter = 0;
for (int j = 0; j < x.length; j++) {
if (x[j] != 0) {
x[counter++] = x[j];
}
}
while (counter < x.length) {
x[counter++] = 0;
}
printArray(x);
}

Another way to solve this problem is to create a secondary array of the same size, then do this:
Iterate through the first array. If the number is non-zero, put it into the second array, keeping a counter for the second array starting from 0, increasing by 1 whenever you add an element into it.
Since int arrays initialize to 0, after you go through the initial array once, you'll be done. The second array will hold the answer.
// create your initial array x the same way as before
int[] y = new int[x.length];
int counter = 0;
for(int i = 0; i < x.length; i++) {
if(x[i] != 0) {
y[counter] = x[i];
counter++;
}
}

This part looks reasonable
for(int j = 0; j < x.length; j++){
if(x[j]!=0){
x[counter] = x[j];
counter++;
}
}
It puts all non-zero elements into the beginning of the array. The problem is the else-part, which overwrites elements at the end of the array. Since you already know that only zeros belong to the end of the array, just fill the array with zeros, beginning at counter.

You can do in following simple way also : (It consist of logic for changes in array. As reading from file and storing in array is pretty clear to u.)
package SO;
public class ZeroAtEnd {
public static void main(String[] args) {
int[] arr = new int[] { 0, 6, 13, 0, 0, 75, 33, 0, 0, 0, 4, 2, 9, 21, 0, 86, 0, 32, 66, 0, 0 };
arr = makeZeroAtEnd(arr);
}
private static int[] makeZeroAtEnd(int[] arr) {
int l = arr.length;
int leftCounter = 0;
int rightCounter = l - 1;
int[] finalArr = new int[l];
for (int i = 0; i < l; i++) {
if (arr[i] == 0) {
// put at end
finalArr[rightCounter] = arr[i];
rightCounter--;
} else {
// put at beginning.
finalArr[leftCounter] = arr[i];
leftCounter++;
}
}
for (int i : finalArr)
System.out.println(i);
return finalArr;
}
}
OUTPUT
6
13
75
33
4
2
9
21
86
32
66
0
0
0
0
0
0
0
0
0
0

Related

Move all zeroes in a given array to the end and replace each non-zero element with the closest greater value, if any

Looking for the optimised solution for the below problem.
Given an unsorted array, we are required to move all zeroes to the end of the array and at same time find the next closest greater number of each element(non-zero) and return the same element incase if there is no next greater element for an element in the array .
Input = {6,1,5,0,0,3,8,6,4}
Output = {8,3,6,4,8,6,4,0,0}
I tried the below :
public class next_closest_element {
public static void main(String[] arg) {
int[] input = {6, 1, 5, 0, 0, 3, 8, 6, 4};
Stack<Integer> stack = new Stack<Integer>();
int k = 0;
int count = 0;
int last_index_value =input.length-1;
for (int i = 0; i < input.length; i++) {
if (input[i] != 0) {
int j = i + 1;
boolean flag = false;
while (j < input.length && input[i] != 0) {
if (input[j] > input[i]) {
if (stack.empty() || !flag) {
stack.push(input[j]);
flag = true;
j++;
} else if (stack.peek() > input[j]) {
stack.pop();
stack.push(input[j]);
flag = true;
j++;
} else {
j++;
}
} else {
j++;
}
}
if (flag) {
input[k] = stack.peek();
k++;
}
else {
input[k]=input[i];
k++;
}
}
else{
count +=1;
}
}
while(count>0){
input[last_index_value]=0;
last_index_value--;
count--;
}
for (int s :
input) {
System.out.println(s);
}
}
}
First shoveling the zeroes to the right would be one optimisation.
Possibly replacing with next closest greater element I have interpreted as next following element (as you seemed to do, as otherwise the last 4 might have become the overwritten 5).
static int[] f(int[] values) {
// In-situ (in-place) algorithm.
int n = 0; // The count of non-zero values.
for (int i = 0; i < values.length; ++i) {
if (values[i] != 0) {
values[n] = values[i];
++n;
}
}
// Zero the rest:
// (With a second array the remaining values from n upwards would
// already be zero.)
for (int i = n; i < values.length; ++i) {
values[i] = 0;
}
// {6, 1, 5, 0, 0, 3, 8, 6, 4} -> {6, 1, 5, 3, 8, 6, 4, [n] 0, 0}
// (First optimisation.) Now we only need to deal with n non-zero values.
// Search the next (A) closest greatest (B) number, when found substitute.
// Unoptimized:
for (int i = 0; i < n; ++i) {
int ithValue = values[i];
boolean hasClosest = false;
int closest = Integer.MAX_VALUE;
for (int j = i + 1; j < n; ++j) {
int jthValue = values[j];
if (jthValue > ithValue && (!hasClosest || jthValue < closest)) {
closest = jthValue;
hasClosest = true;
values[i] = jthValue;
}
}
}
// {8, 3, 6, 4, 8, 6, 4, 0, 0}
return values;
}
public static void main(String[] args) {
int[] input = {6, 1, 5, 0, 0, 3, 8, 6, 4};
System.out.println(Arrays.toString(f(input)));
}
The last piece is not well optimized.
An other interpretation of "closest greatest:"
int[] sorted = Arrays.copyOf(values, n);
Arrays.sort(sorted);
for (int i = 0; i < n; ++i) {
int j = Arrays.binarySearch(sorted, values[i] + 1);
if (j < 0) { // Not found 1 greater.
j = ~j; // Even greater.
}
if (j < n) {
values[i] = sorted[j];
}
}
// {8, 3, 6, 4, 8, 8, 5, 0, 0}
Sorting cost O(N log N), as does the loop O(N) times binary search O(log N).
So it is faster, costing memory. But that is comparible with you stack usage.
By the way, a cleaned up version of your code could have been put on CodeReview.

Duplicate zero in array by modifying the array in place

There is a fixed length array arr of integers, duplicate each occurrence of zero, shifting the remaining elements to the right. The elements beyond the length of the original array are not written.
We have to modify input array in place and doesn't have to create new array.
So I created that but it is duplicating the zero which is at the end of array and not the previous zeros. Can somebody help me with this?
public static void addPos() {
int arr[] = { 1, 2, 0, 3, 0, 5, 0, 7, 8 };
int result[] = new int[arr.length];
for (int i = 0; i < arr.length; i++) {
if (arr[i] == 0) {
int loc = i;
for (int j = 0; j < loc; j++) {
result[j] = arr[j];
result[loc] = 0;
}
for (int j = loc + 1; j < arr.length; j++) {
result[j] = arr[j - 1];
}
}
}
for (int k = 0; k < arr.length; k++)
System.out.println(result[k]);
}
Output
1
2
0
3
0
5
0
0
7
Expected output:
1
2
0
0
3
0
0
5
0
Every iteration of the loop overwrites the results from the previous iteration, so the end result only shows the results from the last iteration, which duplicates the last 0 is duplicated.
One way to solve this is by iterating backwards "right to left". It simplifies a lot of things. You can get rid of the auxiliary result array. The basic idea is, go backwards in the array, and every time you find a 0, you duplicate it by rewriting the array to the right of the zero.
public static void addPos() {
int arr[] = {1, 2, 0, 3, 0, 5, 0, 7, 8};
for (int i = arr.length - 1; i >= 0; i--) {
if (arr[i] == 0) {
// duplicate it!
for (int j = arr.length - 1; j > i; j--) {
arr[j] = arr[j-1];
}
}
}
for (int k = 0; k < arr.length; k++) {
System.out.println(arr[k]);
}
}
The for loop keeps overwriting the values in result array, hence the result shows only last duplication.You should not be using the result array at all.Keep shipting values in the original array itself.
You can refer to below code.
for(int i=0;i<arr.length-1;i++){
if(arr[i]==0){
for(int j=arr.length-1;j>i;j--){
arr[j]=arr[j-1];
}
i++;
}
}
public void duplicateZeros(int[] arr)
{
int i=0;
while(i<arr.length)
{
if(arr[i]==0)
{
int j=arr.length-1;
while(j != i)
{
arr[j]=arr[j-1];
j--;
}
i=i+2;
}
else
{
i=i+1;
}
}
}
Without using any other Array.
class Solution {
public void duplicateZeros(int[] arr) {
for(int i=0;i<arr.length;i++){
if(arr[i]==0){
for(int j=arr.length-1;j>i;j--){
arr[j]=arr[j-1];
}
i=i+1;
}
}
}
}
So one has this:
int[] arr = { 1, 2, 0, 3, 0, 5, 0, 7, 8 };
public static void duplicateZeros(int[] arr) {
and should get
{ 1, 2, 0, 3, 0, 5, 0, 7, 8 }
v___
{ 1, 2, 0, 0, 3, 0, 5, 0, 7 }
v___
{ 1, 2, 0, 0, 3, 0, 0, 5, 0 }
This looks like:
for (int i = 1; i < n; ++i) {
if (arr[i - 1] == 0) {
insert at i a 0;
}
}
insert at i a 0:
// First move the remaining to the right: i .. n-2
...
// Then fill in the zero
arr[i] = 0;
Python solution for anyone interested adapted from here
the solution is non-trivial if you do not separate the action of the pointer iterating over the list and the insertions. It's very easy to write a for-loop that adds 0's ad-infinitum.
def duplicateZeros(arr):
# define the incrementor
i = 0
# loop through all dynamic elements
while i < len(arr)-1:
# if the character is a zero
if arr[i]==0:
# remove the last item from the array
arr.pop()
# insert a zero in front of current element
arr.insert(i+1, 0)
# move one place forward
i += 1
# increment to the next character
i += 1
Solution 1: Loop from start to end. If zero is found, move the elements from next index and fill the next as zero and skip next.
public static void duplicateZeros(int[] arr) {
System.out.println("BEGIN duplicateZeros:" + Arrays.toString(arr));
for(int i=0; i<arr.length-1; ++i) {
if (arr[i] == 0) {
move(arr, i);
++i;
}
}
System.out.println("END duplicateZeros:" + Arrays.toString(arr) +"\n");
}
private static void move(int[] arr, int index) {
// move to the right from index+1
for(int i=arr.length-1; i>index; i--) {
arr[i] = arr[i-1];
}
// fill 0 at index
arr[index] = 0 ;
}
Solution2: Loop from end to start. If zero is found, move the elements from next index and fill the current index as zero.
public static void duplicateZeros(int[] arr) {
System.out.println("BEGIN duplicateZeros:" + Arrays.toString(arr));
for(int i=arr.length-1; i>=0; i--) {
if (arr[i] == 0) {
move(arr, i);
}
}
System.out.println("END duplicateZeros:" + Arrays.toString(arr) +"\n");
}
private static void move(int[] arr, int index) {
// move to the right from index+1
for(int i=arr.length-1; i>index; i--) {
arr[i] = arr[i-1];
}
// fill 0 at index
arr[index] = 0 ;
}
class Solution:
def duplicateZeros(self, arr: List[int]) -> None:
"""
Do not return anything, modify arr in-place instead.
"""
if len(arr)==0:
return arr
index = 0
while index < len(arr):
print(index,end=" ")
if arr[index]==0:
arr.insert(index+1,0)
arr.pop()
index+=1
index+=1

Convert int array to directions

I have a code snippet (see snippet below) that generates an array like this: [0, 3, 1, -2, 0, -1, 1, 1, -2]. The int numbers here represent movements from one position to another. I would like to have the numerical values translated into text that would represent directions starting from the 0. A Positive number represents the number of steps to the East--so the number 3 would be translated into "eee", the number two would be "ee" and so on. Negative values represents steps in the opposite direct West so that -2 would be displayed as ww, and so on. No movement should be represented as 0.
I'm pretty new to all this and am not sure how the take the values from the array and turn them into the instructions as described above.
The code below shows how the array of integers is generated--subtracting the next location from the previous to get the number of steps between them.
int [] differenceX = new int [noOfRecordsX];
differenceX [0] = 0;
for( int i=0; i < noOfRecordsX -1 ;i++)
{
differenceX [i+1]= inputX [i+1] - inputX[i];
}
From here I want to generate the text describing the steps in the respective direction so that this array:
[0, 3, 1, -2, 0, -1, 1, 1, -2]
would be transformed to this string:
0,eee,e,ww,0,w,e,e,ww
If you wish to get the string back instead of just writing to the console try this:
private void testMyMethod(){
String resultString = "";
int[] array = { 0, 3, 1, -2, 0, -1, 1, 1, -2 };
for(int step : array){
String direction = convertToDirection(step);
// Adding a comma -- as you requested
// just add this in case you what to indicate a start point ==> X
if(direction.isEmpty()){
resultString = resultString.concat("X");
}
else{
resultString = resultString.concat(direction);
}
resultString = resultString.concat(",");
}
resultString = resultString.subString(0, resultString.length()-1);
myTextView.setText(resultString);
}
private String convertToDirection(int step){
String direction = "";
if(step > 0){
direction = "e";
}
else if(step < 0){
direction = "w";
}
String result = "";
int len = Math.abs(step);
for(int i = 0; i < len; i++){
result = result.concat(direction);
}
return result;
}
Edit:
A less verbose solution:
private void testMyMethod(){
int[] array = { 0, 3, 1, -2, 0, -1, 1, 1, -2 };
StringBuilder sb = new StringBuilder();
for(int step : array){
sb.append(convertToDirection(step).concat(","));
}
// Remove the last ","
sb.deleteCharAt(sb.length()-1);
myTextView.setText(sb.toString());
}
private String convertToDirection(int step){
if(step == 0) return "0";
String direction = step > 0 ? "w" : "e";
int len = Math.abs(step);
return new String(new char[len]).replace("\0", direction);
}
Borrowing this: new String(new char[len]).replace("\0", direction); from this solution:
Repeat String
You can do so by using the following code :
int arr[] = { 0, 3, 1, -2, 0, -1, 1, 1, -2 };
for (int i = 0; i < arr.length; i++) {
if (arr[i] < 0) { // west
for (int j = arr[i]; j < 0; j++) {
System.out.println("w");
}
} else if (arr[i] > 0) { // east
for (int j = 0; j < arr[i]; j++) {
System.out.println("e");
}
}
}
If the number is negative then we iterate from that value upto 0.
If the number is positive then we iterate from 0 upto that value.
We should better use char repeating instead of loops. Look at Simple way to repeat a String in java for different ways.
int arr[] = { 0, 3, 1, -2, 0, -1, 1, 1, -2 };
StringBuilder output = new StringBuilder();
for(int step : array){
int length = Math.abs(step);
if (step < 0) { // west
output.append(new String(new char[length]).replace("\0", "w"));
}
else if (step > 0) { // east
output.append(new String(new char[length]).replace("\0", "e"));
}
else output.append("0");
}
}

Java MergeSort Algorithm recursive

i have a small question.
I try to implement the merge sort algorithm recursive.
int sort_list[] = {5, 9, 7, 8, 3, 4, 5, 6, 1, 0};
int[] left = new int[sort_list.length];
int[] right = new int[sort_list.length];
public Mergesort() {
int[] lv_sorted_list = mergeSort(sort_list);
for (int i = 0; i < lv_sorted_list.length; i++) {
System.out.print(" " + lv_sorted_list[i] + ", ");
}
}
int[] mergeSort(int[] iv_sort_list) {
for (int i = 0; i < iv_sort_list.length; i++) {
System.out.print("Divide: " + iv_sort_list[i] + " ");
}
System.out.println("");
if (iv_sort_list.length > 1) {
left = mergeSort(Arrays.copyOfRange(iv_sort_list, 0, iv_sort_list.length / 2));
right = mergeSort(Arrays.copyOfRange(iv_sort_list, iv_sort_list.length / 2, iv_sort_list.length));
}
int i = 0;
int j = 0;
int[] sorted_list = new int[left.length + right.length];
while (i < left.length && j < right.length) {
if (left[i] > right[j]) {
int tmp = left[i];
left[i] = right[j];
right[j] = tmp;
System.arraycopy(left, 0, sorted_list, 0, left.length);
System.arraycopy(right, 0, sorted_list, left.length, right.length);
i++;
j++;
}else{
break;
}
return sorted_list;
}
Now my Question:
left = mergeSort(Arrays.copyOfRange(iv_sort_list, 0, iv_sort_list.length));
right = mergeSort(Arrays.copyOfRange(iv_sort_list, iv_sort_list.length, iv_sort_list.length));
If i try to assign my left / right array "mergeSort(...)", then it will be assign only a new array with new length, which contains in every position the value 0.
Thank you very much for your help :)
I think you are missing the base case iv_sort_list.length = 1 or iv_sort_list.length = 2 (depends on your implementation) in your recursion function.
Your left[] and right[] should be declare inside each recursion call? As you are using there length property a lot, you will get wrong if you declare as global with a fixed length.
Also your merging code seems a bit messy, I have modified a bit and now it should work, please see the example here: Merge Sort (Java) demo

Appending Integer array elements in Java

I have an array, say
int a[]={2,0,1,0,1,1,0,2,1,1,1,0,1,0,1};
I need to append each of the 5 neighboring elements and assign them to a new array b with length=(a.length/5); and i want to append the 5 neighboring elements so that I have:
int b[]={20101,10211,10101}; I need to do this for various length arrays, in most cases with length of a being greater than 15.
Any help would be greatly appreciated, I'm programming in Java.
Thanks in advance.
It's pretty straighforward:
// Assuming a.length % 5 == 0.
int[] b = new int[a.length / 5];
for (int i = 0; i < a.length; i += 5) {
b[i/5] = a[i]*10000 + a[i+1]*1000 + a[i+2]*100 + a[i+3]*10 + a[i+4];
}
This sounds like a homework question, so I won't give you the complete solution, but the basic rundown is:
Compute the length of b: len = a.length / 5
Construct b with that many elements.
Initialize an index variable to point to the first element in a
For each element in b:
Construct the value for that element from a[idx]...a[idx+4]
Advance the index into a by 5.
Also note that you may need to verify that the input a is actually a multiple of 5 in length.
This works with (a.length % 5) != 0, and keeps leading zeroes (by storing digits into String).
int a[]={2,0,1,0,1,1,0,2,1,1,1,0,1,0,1,0,0,7};
final int N = 5;
String b[] = new String[(a.length + N - 1)/ N];
StringBuilder sb = new StringBuilder(N);
int x = 0;
for (int i = 0; i < b.length; i++) {
sb.setLength(0);
for (int k = 0; k < N && x < a.length; k++) {
sb.append(a[x++]);
}
b[i] = sb.toString();
}
System.out.println(java.util.Arrays.toString(b));
// prints "[20101, 10211, 10101, 007]"
Alternately, you can also use regex:
String[] arr =
java.util.Arrays.toString(a)
.replaceAll("\\D", "")
.split("(?<=\\G.{5})");
System.out.println(java.util.Arrays.toString(arr));
// prints "[20101, 10211, 10101, 007]"
Basically this uses Arrays.toString(int[]) to append all digits into one long String, then removes all non-digits \D, then uses \G-anchored lookbehind to split every .{5}
Naive approach.
import java.util.ArrayList;
/* Naive approach */
public class j2728476 {
public static void main(String[] args) {
int a[] = {2,0,1,0,1,1,0,2,1,1,1,0,1,0,1};
ArrayList<String> al = new ArrayList<String>();
String s = "";
for (int i = 0; i < a.length; i++) {
if (i % 5 == 0 && i != 0) {
al.add(s);
s = "" + a[i];
} else {
s += a[i];
}
}
al.add(s);
for (String t : al) {
// convert values to ints ...
System.out.println(t);
}
}
}
Will print:
20101
10211
10101
import java.util.Arrays;
public class MainClass {
public static void main(String args[]) throws Exception {
int array[] = { 2, 5, -2, 6, -3, 8, 0, -7, -9, 4 };
Arrays.sort(array);
printArray("Sorted array", array);
int index = Arrays.binarySearch(array, 1);
System.out.println("Didn't find 1 # "
+ index);
int newIndex = -index - 1;
array = insertElement(array, 1, newIndex);
printArray("With 1 added", array);
}
private static void printArray(String message, int array[]) {
System.out.println(message
+ ": [length: " + array.length + "]");
for (int i = 0; i < array.length; i++) {
if (i != 0){
System.out.print(", ");
}
System.out.print(array[i]);
}
System.out.println();
}
private static int[] insertElement(int original[],
int element, int index) {
int length = original.length;
int destination[] = new int[length + 1];
System.arraycopy(original, 0, destination, 0, index);
destination[index] = element;
System.arraycopy(original, index, destination, index
+ 1, length - index);
return destination;
}
}
It will print
Sorted array: [length: 10]
-9, -7, -3, -2, 0, 2, 4, 5, 6, 8
Didn't find 1 # -6
With 1 added: [length: 11]
-9, -7, -3, -2, 0, 1, 2, 4, 5, 6, 8

Categories