Iterating an array from both ends using two indices - java

This is more of an self defined programming exercise than a real problem. I have an array of java.lang.Comparable items. I need to maintain two pointers (an index into the array i.e., int values) i,j . i starts at the beginning of array and moves right until it encounters an element which is less than or equal to the previous element. When it does it stops moving right and ends up pointing to the element which is out of order(element which is not greater than the previous). Similarly j starts at the end of the array and moves left until it finds an element which is not less than the previous.
Also, I need to make sure that the indices don't run out of the array i.e., i cannot go below 0 and j cannot go above arraylength-1
lets say we have an array of 5 elements.
i = 0;
j = 4;(which is the arraylength-1 )
if C,D,E,F,G is the array ,the final values of i and j will be
i = 4 and j = 0
if array is J,D,E,F,G ,the final values of i, j will be
i = 0 , j = 0
if array is B,C,A,D,G , final values of i,j will be
i = 2 , j = 1
I tried to code the logic for moving i to the right, using a while loop as below. I was able to get it working for the i pointer in two cases.
public class PointerMovement{
public static void ptrsPointToOutOfOrderElements(Comparable[] a){
int lo = 0;
int hi = a.length-1;
int i = lo;
int t=i+1;
int j = hi;
//only for moving i to the right .
while(less(a[i],a[t])){
if(t == hi){
i=t;
break;
}
i++;
t++;
}
i=t;
for(Comparable x:a){
System.out.print(x+",");
}
System.out.println();
System.out.println("bad element or end of array at i="+i+"==>"+a[i]);
}
private static boolean less(Comparable x,Comparable y){
return x.compareTo(y) < 0;
}
public static void main(String[] args) {
String[] a = new String[]{"C","D","E","F","G"};//works
//String[] a = new String[]{"B","C","A","D","G"};//works
//String[] a = new String[]{"J","D","E","F","G"};//fails!
ptrsPointToOutOfOrderElements(a);
}
}
My line of reasoning given below
I maintain i=0; and another variable t=i+1
when the while loop fails, less(a[i],a[t]) is false .We need to return a pointer to a[t] which is out of order. so i=t and return i.
if we reach right end of array, the test if(t == hi) passes and we assign i=t and now i points to end of array.
However, the code fails when the out of order element is in the 0th position in the array.
J,D,E,F,G
Instead of i (=0) we get i=1 because i=t is assgined.i ends up pointing to D instead of J.
Can someone point me in the right direction?
update:
this seems to work
public static void ptrsPointToOutOfOrderElements(Comparable[] a){
int lo = 0;
int hi = a.length-1;
int i = lo;
while(less(a[i],a[i+1])){
if(i+1 == hi){
break;
}
i++;
}
i++;
int j = hi;
while(less(a[j-1],a[j])){
if(j-1 == lo){
break;
}
j--;
}
j--;
for(Comparable x:a){
System.out.print(x+",");
}
System.out.println();
if(i>=j){
System.out.println("pointers crossed");
}
System.out.println("bad element or end of array at i="+i+"==>"+a[i]);
System.out.println("bad element or end of array at j="+j+"==>"+a[j]);
}

I do not think you have a problem:
String[] a = new String[]{"C","D","E","F","G"};//works, index should be 4 (but should it be so? It would indicate that G is out of order while it is not. I think you should return 5, indicating that none is out of order.
String[] a = new String[]{"B","C","A","D","G"};//works, index should be 2 as A is out of order
String[] a = new String[]{"J","D","E","F","G"};//works since the first out of order element is indeed D, with index 1

I have tried using simple for loop.
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (var i = 0, j = arr.length - 1; i <= j; i++, j--) {
console.log(arr[i] + ' , ' + arr[j]);
}
Output :
1 , 10
2 , 9
3 , 8
4 , 7
5 , 6

Related

Creating a method that merges 2 arrays into one sorted array in ascending order in Java

For part of an assignment, I have to create a method that merges 2 arrays into one sorted array in ascending order. I have most of it done, but I am getting a bug that replaces the last element in the array with 0. Has anyone ever run into this problem and know a solution? Heres my code:
public static OrderedArray merge(OrderedArray src1, OrderedArray src2) {
int numLength1 = src1.array.length;
int numLength2 = src2.array.length;
//combined array lengths
int myLength = (numLength1 + numLength2);
// System.out.println(myLength);
OrderedArray mergedArr = new OrderedArray(myLength);
//new array
long[] merged = new long[myLength];
//loop to sort array
int i = 0;
int j = 0;
int k = 0;
while (k < src1.array.length + src2.array.length - 1) {
if(src1.array[i] < src2.array[j]) {
merged[k] = src1.array[i];
i++;
}
else {
merged[k] = src2.array[j];
j++;
}
k++;
}
//loop to print result
for(int x = 0; x < myLength; x++) {
System.out.println(merged[x]);
}
return mergedArr;
}
public static void main(String[] args) {
int maxSize = 100; // array size
// OrderedArray arr; // reference to array
OrderedArray src1 = new OrderedArray(4);
OrderedArray src2 = new OrderedArray(5);
// arr = new OrderedArray(maxSize); // create the array
src1.insert(1); //insert src1
src1.insert(17);
src1.insert(42);
src1.insert(55);
src2.insert(8); //insert src2
src2.insert(13);
src2.insert(21);
src2.insert(32);
src2.insert(69);
OrderedArray myArray = merge(src1, src2);
This is my expected output:
1
8
13
17
21
32
42
55
69
and this is my current output:
1
8
13
17
21
32
42
55
0
While merging two arrays you are comparing them, sorting and merging but what if the length of two arrays is different like Array1{1,3,8} and Array2{4,5,9,10,11}. Here we will compare both arrays and move the pointer ahead, but when the pointer comes at 8 in array1 and at 9 in array2, now we cannot compare ahead, so we will add the remaining sorted array;
Solution:-
(Add this code between loop to sort array and loop to print array)
while (i < numLength1) {
merged[k] = src1.array[i];
i++;
k++;
}
while (j < numLength2) {
merged[k] = src2.array[j];
j++;
k++;
}
To answer your main question, the length of your target array is src1.array.length + src2.array.length, so your loop condition should be one of:
while (k < src1.array.length + src2.array.length) {
while (k <= src1.array.length + src2.array.length - 1) {
Otherwise, you will never set a value for the last element, where k == src1.array.length + src2.array.length - 1.
But depending on how comprehensively you test the code, you may then find you have a bigger problem: ArrayIndexOutOfBoundsException. Before trying to use any array index, such as src1.array[i], you need to be sure it is valid. This condition:
if(src1.array[i] < src2.array[j]) {
does not verify that i is a valid index of src1.array or that j is a valid index of src2.array. When one array has been fully consumed, checking this condition will cause your program to fail. You can see this with input arrays like { 1, 2 } & { 1 }.
This revision of the code does the proper bounds checks:
if (i >= src1.array.length) {
// src1 is fully consumed
merged[k] = src2.array[j];
j++;
} else if (j >= src2.array.length || src1.array[i] < src2.array[j]) {
// src2 is fully consumed OR src1's next is less than src2's next
merged[k] = src1.array[i];
i++;
} else {
merged[k] = src2.array[j];
j++;
}
Note that we do not need to check j in the first condition because i >= src1.array.length implies that j is a safe value, due to your loop's condition and the math of how you are incrementing those variables:
k == i + j due to parity between k's incrementing and i & j's mutually exclusive incrementing
k < src1.array.length + src2.array.length due to the loop condition
Therefore i + j < src1.array.length + src2.array.length
If both i >= src1.array.length and j >= src2.array.length then i + j >= src1.array.length + src2.array.length, violating the facts above.
A couple other points and things to think about:
Be consistent with how you refer to data. If you have variables, use them. Either use numLength1 & numLength2 or use src1.length & src2.length. Either use myLength or use src1.array.length + src2.array.length.
Should a merge method really output its own results, or should the code that called the method (main) handle all the input & output?
Is the OrderedArray class safe to trust as "ordered", and is it doing its job properly, if you can directly access its internal data like src1.array and make modifications to the array?
The best way to merge two arrays without repetitive items in sorted order is that insert both of them into treeSet just like the following:
public static int[] merge(int[] src1, int[] src2) {
TreeSet<Integer> mergedArray= new TreeSet<>();
for (int i = 0; i < src1.length; i++) {
mergedArray.add(src1[i]);
}
for (int i = 0; i < src2.length; i++) {
mergedArray.add(src2[i]);
}
return mergedArray.stream().mapToInt(e->(int)e).toArray();
}
public static void main(String[] argh) {
int[] src1 = {1,17,42,55};
int[] src2 = {8,13,21,32,69};
Arrays.stream(merge(src1,src2)).forEach(s-> System.out.println(s));
}
output:
1
8
13
17
21
32
42
55
69

Trying to create a array with the intersection of two arrays but fails at creating array with the proper structure

So, I am trying to create 2 randomly generated arrays,(a, and b, each with 10 unique whole numbers from 0 to 20), and then creating 2 arrays with the info of the last two. One containing the numbers that appear in both a and b, and another with the numbers that are unique to a and to b. The arrays must be listed in a "a -> [1, 2, 3,...]" format. At the moment I only know how to generate the 2 arrays, and am currently at the Intersection part. The problem is, that I can create a array with the correct list of numbers, but it will have the same length of the other two, and the spaces where it shouldn't have anything, it will be filled with 0s when its supposed to create a smaller array with only the right numbers.
package tps.tp1.pack2Arrays;
public class P02ArraysExtractUniqsAndReps {
public static void main(String[] args) {
int nbr = 10;
int min = 0;
int max = 20;
generateArray(nbr, min, max);
System.out.println();
}
public static int[] generateArray(int nbr, int min, int max) {
int[] a = new int[nbr];
int[] b = new int[nbr];
int[] s = new int[nbr];
s[0] = 0;
for (int i = 0; i < a.length; i++) {
a[i] = (int) (Math.random() * (max - min));
b[i] = (int) (Math.random() * (max - min));
for (int j = 0; j < i; j++) {
if (a[i] == a[j]) {
i--;
}
if (b[i] == b[j]) {
i--;
}
}
}
System.out.println("a - > " + Arrays.toString(a));
System.out.println("b - > " + Arrays.toString(b));
for (int k = 0; k < a.length; k++) {
for (int l = 0; l < b.length; l++) {
if (a[k] == b[l]) {
s[l] = b[l];
}else {
}
}
}
System.out.println("(a ∪ (b/(a ∩ b)) - > " + Arrays.toString(s));
return null;
}
public static boolean hasValue(int[] array, int value) {
for (int i = 0; i < array.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
}
Is there any way to create the array without the incorrect 0s? (I say incorrect because it is possible to have 0 in both a and b).
Any help/clarification is appreciated.
First, allocate an array large enough to hold the intersection. It needs to be no bigger that the smaller of the source arrays.
When you add a value to the intersection array, always add it starting at the beginning of the array. Use a counter to update the next position. This also allows the value 0 to be a valid value.
Then when finished. use Array.copyOf() to copy only the first part of the array to itself, thus removing the empty (unfilled 0 value) spaces. This works as follow assuming count is the index you have been using to add to the array: Assume count = 3
int[] inter = {1,2,3,0,0,0,0};
inter = Arrays.copyOf(inter, count);
System.out.println(Arrays.toString(inter);
prints
[1,2,3]
Here is an approach using a List
int[] b = {4,3,1,2,5,0,2};
int [] a = {3,5,2,3,7,8,2,0,9,10};
Add one of the arrays to the list.
List<Integer> list = new ArrayList<>();
for(int i : a) {
list.add(i);
}
Allocate the intersection array with count used as the next location. It doesn't matter which array's length you use.
int count = 0;
int [] intersection = new int[a.length];
Now simply iterate thru the other array.
if the list contains the value, add it to the intersection array.
then remove it from the list and increment count. NOTE - The removed value must be converted to an Integer object, otherwise, if a simple int value, it would be interpreted as an index and the value at that index would be removed and not the actual value itself (or an Exception might be thrown).
once finished the intersection array will have the values and probably unseen zeroes at the end.
for(int i = 0; i < b.length; i++) {
int val = b[i];
if (list.contains(val)) {
intersection[count++] = val;
list.remove(Integer.valueOf(val));
}
}
To shorten the array, use the copy method mentioned above.
intersection = Arrays.copyOf(intersection, count);
System.out.println(Arrays.toString(intersection));
prints
[3, 2, 5, 0, 2]
Note that it does not matter which array is which. If you reverse the arrays for a and b above, the same intersection will result, albeit in a different order.
The first thing I notice is that you are declaring your intersection array at the top of the method.
int[] s = new int[nbr];
You are declaring the same amount of space for the array regardless of the amount you actually use.
Method Arrays.toString(int []) will print any uninitialized slots in the array as "0"
There are several different approaches you can take here:
You can delay initializing the array until you have determined the size of the set you are dealing with.
You can transfer your content into another well sized array after figuring out your result set.
You could forego using Array.toString, and build the string up yourself.

Creating a program that increments Arrays

An integer array stores values 3,2,3,4,5. I am trying to create a program that increments these values by 2 and then saves the result into the same array using a for loop. I tried but something is wrong with my code, here:
public class ArrayClass {
int a[] = {2, 3, 3, 4, 5};
}
public class ArrayObject {
public static void main(String[] Ella) {
int a[] = new int[5];
int i;
for (i = 2; i < a.length; i = i + 2) {
a[i] = i + 2;
System.out.println(a[i]);
}
}
}
This should work:
for (i = 0; i < a.length; i++) {
a[i] += 2;
System.out.println(a[i]);
}
You see, when increasing every single value of an array, the index has to be 0 and max the array's length. By adding one to i, the indexing of the array increases by one, which means the next number will be increased by two. what you did was add two to the "i" variable which means that only 3 of the varialbes would have been changed.
Please make below change to your code.It will work.
for (i = 0; i < a.length; i++) {
a[i] = a[i] + 2;
System.out.println(a[i]);
}
The error is that when you do i = i + 2, you are just incrementing the position index, not the actual value in that position.
you need to do:
a[i] = a[i]+2;
Let me explain what a[i] is:
|3|2|3|4|5|
1 2 3 4 5
The first row are the values. The second row is the index. "Index" means the position number of each of positions in the array.
Another problem is that, when you initialise i, it need to be i=0. That is because i array indices (plural of index) always start from 0. That means that a[0] is the first position in the array That would be number 3 from your data set.

adding element to stack

I create a method in stack call adding in this method I want to add element after the element is specific form use for example if the number in stack is "1 2 3 5" and I choose number 3 and enter number 4 the stack should be "1 2 3 4 5" this my trying
int a[] = new int[6];
int Top = -1;
public void push() {
if (Top > 6) {
System.out.println(" the Stack Ovelflow");
} else {
Top = Top + 1;
String m = JOptionPane.showInputDialog("enter the element stack");
a[Top] = Integer.parseInt(m);
}
}
public void adding() {
String s = JOptionPane.showInputDialog("enter the element u want to add after it");
int x = Integer.parseInt(s);
String s2 = JOptionPane.showInputDialog("enter the element u want to add to stack");
int d = Integer.parseInt(s2);
for (int i = 0; i < a.length; i++) {
if (a[i] == x) {
a[i + 1] = d;
}
}
}
You need to make sure that your backing array a has enough space, so you can insert a new element.
int[] a= new int[]{1,2,3,5}; // this has only 4 elements, you can't add a 5th
So you could do:
public void adding(){
// ask user for input.... and all that
// you need an array with one more element than a. lets call it b
int[] b = new int[a.length + 1];
// now you need to search for x. (this is, if x is a number in your array and not an index..it wasn't clear to me)
// so if x is a number in the array (and not the index) you need to get the index of that number:
int index = 0;
for (; index < a.length; index++) { // your index variable will increment on each step
if (a[index] == x) {
break; // and you break out of the loop once you found x
}
}
// now you know the index of x
// first make a copy of the partial array after x (in your example its just {5})
int[] c = Arrays.copyOfRange(a, index, a.length); // this will copy all elements of a from "index" to "length"
// and here the loop that will actually insert the new number and move the rest:
int cIndex=0; // we need that counter later to loop through the new array c
for (int i = 0; i < b.length; i++) { // loop through every element of b
if (i <= index) { // if i is currently smaller than your wanted index (there where you will find x)
b[i] = a[i]; // then just copy the contents of a
} else if (i == index+1) { // we just stepped over x
b[i] = d; // so you can add your new number here
} else {
b[i] = c[cIndex]; // and here you copy the rest into b (the partial array we called c earlier)
cIndex++; // we need that new index, to get always the next element
}
}
And that's it. looks complicated and is by far not the best or most efficient solution. But it works and I hope it helps you getting further!

java- "-1" position

I have this question:
The method accepts an integer array as its input and returns a new array which is a
permutation of the input array. The method fix34 rearranges the input array such
that every 3 is immediately followed by a 4 (e.g. if there is a 3 at position i, there will
be a 4 at position i+1). The method keeps the original positions of the 3s but may
move any other number, moving the minimal amount of numbers.
Assumptions regarding the input:
The array contains the same number of 3's and 4's (for every 3 there is a 4)
There are no two consecutive 3s in the array
The matching 4 for a 3 at some position i is at position j where j > i
ok, so this is what I wrote:
public class Fix34 {
public static void main(String[] args){
int [] args1 ={3,1,2,3,5,4,4};
int[] args11=fix34(args1);
for (int i = 0; i<=args11.length-1;i++ ){
System.out.print(args11[i]+" ");}}
public static int pos (int[] arr){
int i= arr.length-1;
while (arr[i]!=4){
i=-1;
}
return i;
}
public static int[] fix34(int[] nums){
for(int i = 0; i<=nums.length-1; i++){
if (nums[i] == 3){
nums[pos(nums)]=nums[i+1];
nums[i+1]=4;
}
}
return nums;
}
}
when I insert arrays such {3,2,1,4} it works, but with the array as written in the code, it gives me the error message:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: -1
at Fix34.pos(Fix34.java:15)
at Fix34.fix34(Fix34.java:25)
at Fix34.main(Fix34.java:6)
how come the arrays gets to -1 position?!
Thanks
you are setting it to -1 here:
i=-1;
Your issue in in this piece of code
public static int pos (int[] arr){
int i= arr.length-1;
while (arr[i]!=4){
i=-1;
}
return i;
}
If the last element in the array is 4 the while loop is never entered so arrays like 3, 1, 2, 4 are fine. Otherwise the loop is entered and i is set to -1. I think that you mean to decrement. In that case replace
i=-1
with
i--
or
i=i-1
and as mentioned in another answer make sure i doesn't go below 0.
I think you ment
i-= 1;
instead of that:
i=-1;
Whoa there that is a little overblown for this problem. Nested loops are they key here…come take a look
public int[] fix34(int[] nums) {
for(int a = 0; a < nums.length; a++){ //we see 4's first
for(int b = 0; b < nums.length - 1; b++){ //then the nested loop finds a 3
//length - 1 to stay in bounds, although not needed here...
if(nums[a] == 4 && nums[b] == 3){
//swap
int tmp = nums[b + 1];
nums[b + 1] = nums[a];
nums[a] = tmp;
}
}
}
return nums;
}

Categories