How to quickly recover an increasing array with 2 elements randomly swapped? - java

If I have an array A = [1, 2, 3, 4, 5, 6, 7], A is an increasing array, with no duplicate elements. If I swap two elements, let's say 4 and 7. I get array B = [1, 2, 3, 7, 5, 6, 4].
Given array B, what's the fast way to recover A?
Currently, the naive way is using the Collections sort method sort the array and compare to get the two different indexes, this cost O(n) space as well as O(n) time.
To make the question clear, here you are given input B and should output B

Just search the swapped elements starting from the left and from the right and swap them when found.
// Let' assume the array is stored in a variable 'arr'
private void restoreArray() {
swap(getLeftSwapIndex(), getRightSwapIndex());
}
private void swap(int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
private void getLeftSwapIndex() {
for (int i=0 ; i<arr.length-1 ; i++) {
if (arr[i] > arr[i+1]) return i;
}
return 0; // does not happen
}
private void getRightSwapIndex() {
for (int i=arr.length-1 ; i>0 ; i--) {
if (arr[i] < arr[i-1]) return i;
}
return 0; // does not happen
}

Related

Java min heap decrease array size after removing element

I am creating a priority queue (my own in array form) with a minimum heap sort where I am implementing a method which deletes the first element in the priority queue (my array) which is the root. I then call the heapifyNumbers() method on my array again to sort the array in minimum heap again. The problem is just that I cannot decrease from an array, so the last two elements will be duplicate.
This is the delete method I am creating
public void deleteMinimum(int[] array){
array[0] = array[array.length - 1];
heapSort(array);
//here I want to decrease array size by 1 after heap sorting the array
}
Here I just replace the first index with the last index, and then call the heapifyNumbers() method on my array again to sort the array. How do I decrease the array size by 1?
I know arrays cannot be decreased, but I see all implementations of this using arrays so there must be some way like creating a new array maybe?
This is my output:
Before Heap Sort :
[1, 10, 16, 19, 3, 5]
After Heap Sort :
[1, 3, 5, 10, 16, 19]
After deleting :
Here there are duplicate 19
[3, 5, 10, 16, 19, 19]
I have done this arr = Arrays.copyOf(array, array.length -1); but I don't know if it still holds the Log N time complexity
This is my full code if you are interested:
import java.util.*;
public class ObligatoriskOpgave2 {
int[] arr={1,10,16,19,3,5};
public static void buildheap(int []arr) {
/*
* As last non leaf node will be at (arr.length-1)/2
* so we will start from this location for heapifying the elements
* */
for(int i=(arr.length-1)/2; i>=0; i--){
heapifyNumbers(arr,i,arr.length-1);
}
}
public static void heapifyNumbers(int[] arr, int i, int size) {
int left = 2*i+1;
int right = 2*i+2;
int max;
if(left <= size && arr[left] > arr[i]){
max=left;
} else {
max=i;
}
if(right <= size && arr[right] > arr[max]) {
max=right;
}
// If max is not current node, swapCurrentNodeWithMaximumOfChildren it with max of left and right child
if(max!=i) {
swapCurrentNodeWithMaximumOfChildren(arr,i, max);
heapifyNumbers(arr, max,size);
}
}
public static void swapCurrentNodeWithMaximumOfChildren(int[] arr, int i, int j) {
int t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
public static int[] heapSort(int[] arr) {
buildheap(arr);
int sizeOfHeap=arr.length-1;
for(int i=sizeOfHeap; i>0; i--) {
swapCurrentNodeWithMaximumOfChildren(arr,0, i);
sizeOfHeap=sizeOfHeap-1;
heapifyNumbers(arr, 0,sizeOfHeap);
}
return arr;
}
public void deleteMinimum(int[] array){
array[0] = array[array.length - 1];
heapSort(array);
}
public static void main(String[] args) {
ObligatoriskOpgave2 o = new ObligatoriskOpgave2();
System.out.println("Before Heap Sort : ");
System.out.println(Arrays.toString(o.arr));
o.arr=heapSort(o.arr);
System.out.println("=====================");
System.out.println("After Heap Sort : ");
System.out.println(Arrays.toString(o.arr));
o.deleteMinimum(o.arr);
System.out.println(Arrays.toString(o.arr));
}
}
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/arrays.html
An array is a container object that holds a fixed number of values of a single type. The length of an array is established when the array is created. After creation, its length is fixed.
So if you want use array, you must create new array with your new length.
And fill new array with value of old array. (see part Copying Arrays in first link)
The solution was to have a HeapSize int value, which is decreased for each time an element is removed. Next time the array is iterated in a for loop, we don't go further than the heapsize.

Switching the position of two sections of an array

I have an array of integers representing a deck of cards with 52 cards in it, with numbers ranging from 1-52 to represent the cards. I am trying to write a method which will take two positions within the array as parameters to divide the array into three blocks. Block 1 is all the values below the first position, block 2 is all the values lying between the two positions(inclusive of the values at position 1 and 2) and block 3 is all the values lying above the second position. I then want to switch the positions of blocks 1 and 3 within the array.
So for an array with the values of:
1,2,3,4,5,6,7,8,9,10,11,12
Setting positionOne(1), positionTwo(9) would give the array:
11,12,2,3,4,5,6,7,8,9,10,1
Here's what I have so far, which almost works but I think has bugs in it:
public void switchPositions(int pos1, int pos2) {
int[] newCards = new int[cards.length];
int sizeChunkA = 0;
int sizeChunkC = 0;
int sizeChunkB = 0;
int counter = 0;
for(int i = pos2+1; i<cards.length; i++) {
sizeChunkC++;
}
for(int i = 0; i<pos1; i++) {
sizeChunkA++;
}
for(int i = pos1; i<=pos2; i++) {
sizeChunkB++;
}
for(int i = 1; i<=sizeChunkC; i++) {
newCards[counter] = cards[pos2+i];
counter++;
}
for(int i=pos1; i<=pos2; i++) {
newCards[counter] = cards[i];
counter++;
}
for(int i=0; i<sizeChunkA; i++) {
newCards[counter] = cards[i];
counter++;
}
cards = newCards;
}
Is there a better way to do this?
Instead of loops use Arrays.copyOfRange and System.arraycopy:
// make a copy of the first section before overwriting it
int[] copy = Arrays.copyOfRange (inputArray, from, to);
// overwrite the first section with the second section
System.arraysCopy(inputArray, sourcePosition, inputArray, from, copy.length);
// copy the original content of the first section to the second section
System.arraysCopy(copy, 0, inputArray, sourcePosition, copy.length);
You have to change the indices according to your requirements.
I would approach it this way.
Create three arraylists for your three temp blocks.
Iterate through your array starting at 0-> position 1. Moving the values into your first array list.
Iterate through your starting at position 1 and ending at position 2. Moving all values into the sec0nd array list.
Then iterate through your array starting at position 2+1 through to the end.
Combine the three array lists.
There is a bit clearer of a way to do this. If you want to code it yourself rather than just use the existing Arrays.copyOfRange (perhaps if you would like to do it in place rather than generating a new array).
int lengthOfDeck = cards.length;
int[] newCards = new int[lengthOfDeck];
for (int i = 1; i <= lengthOfDeck; i++) {
if (i >=pos1 && i <=pos2) {
newCards[i-1]=i;
}
else if (i < pos1) {
newCards[i-1]= i + pos2;
}
else {
newCards[i-1] = i - pos2;
}
}
What about approach without using additional memory?!
Main idea, is that if you want to shift array to the offs positions right or left you can do it in place with 2 full for loops. I give you example:
Initial array {1,2,3,4,5}; we want to move it 2 positions right (i.e. offs=2), and have result {4,5,1,2,3}
1st loop for reverse all elements: {5,4,3,2,1}
2nd loop for reverse first offs elements: {4,5,3,2,1}
3rd loop for reverse other elements: {4,5,1,2,3}.
That's all! To solve your task, you have to do it twice, but second time you have to reduce array's length to not move last elements.
This is example:
public static void main(String... args) throws IOException {
int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
replace(arr, 1, 9);
// arr = [11, 12, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1]
}
public static void replace(int[] arr, int pos1, int pos2) {
rotate(arr, arr.length, -pos1);
rotate(arr, arr.length - pos1, -pos2);
}
// offs > 0 - to the right; offs < 0 - to the left
private static void rotate(int[] arr, int length, int offs) {
offs = offs >= length ? length % offs : offs;
length = Math.min(arr.length, length);
for (int i = 0, j = length - 1; i < j; i++, j--)
swap(arr, i, j);
for (int i = 0, j = offs > 0 ? offs - 1 : length + offs - 1; i < j; i++, j--)
swap(arr, i, j);
for (int i = offs > 0 ? offs : length + offs, j = length - 1; i < j; i++, j--)
swap(arr, i, j);
}
private static void swap(int[] a, int i, int j) {
int tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
According to the performance. You have 4 full for loops with one swap in each of them. So performance is O(n), without using additional memory.
Thanks to Eran for his tip, here is a more adapted method for your needs:
public int[] splitArray(int[] i, int position1, int position2) {
position2++;
int[] piece1 = Arrays.copyOfRange(i, 0, position1);
int[] piece2 = Arrays.copyOfRange(i, position1, position2);
int[] piece3 = Arrays.copyOfRange(i, position2, i.length);
System.arraycopy(piece3, 0, i, 0, piece3.length);
System.arraycopy(piece2, 0, i, piece3.length, piece2.length);
System.arraycopy(piece1, 0, i, piece3.length+piece2.length, piece1.length);
return i;
}

How can I make an array without one number of the other array?

I am trying to make a code with two arrays. The second array has the same values of the first except for the smallest number. I have already made a code where z is the smallest number. Now I just want to make a new array without z, any feedback would be appreciated.
public static int Second_Tiny() {
int[] ar = {19, 1, 17, 17, -2};
int i;
int z = ar[0];
for (i = 1; i < ar.length; i++) {
if (z >ar[i]) {
z=ar[i];
}
}
}
Java 8 streams have built in functionality that can achieve what you're wanting.
public static void main(String[] args) throws Exception {
int[] ar = {19, 1, 17, 17, -2, -2, -2, -2, 5};
// Find the smallest number
int min = Arrays.stream(ar)
.min()
.getAsInt();
// Make a new array without the smallest number
int[] newAr = Arrays
.stream(ar)
.filter(a -> a > min)
.toArray();
// Display the new array
System.out.println(Arrays.toString(newAr));
}
Results:
[19, 1, 17, 17, 5]
Otherwise, you'd be looking at something like:
public static void main(String[] args) throws Exception {
int[] ar = {19, 1, 17, 17, -2, -2, -2, -2, 5};
// Find the smallest number
// Count how many times the min number appears
int min = ar[0];
int minCount = 0;
for (int a : ar) {
if (minCount == 0 || a < min) {
min = a;
minCount = 1;
} else if (a == min) {
minCount++;
}
}
// Make a new array without the smallest number
int[] newAr = new int[ar.length - minCount];
int newIndex = 0;
for (int a : ar) {
if (a != min) {
newAr[newIndex] = a;
newIndex++;
}
}
// Display the new array
System.out.println(Arrays.toString(newAr));
}
Results:
[19, 1, 17, 17, 5]
I think the OP is on wrong track seeing his this comment:
"I am trying to find out the second smallest integer in array ar[]. I
should get an output of 1 once I am done. The way I want to achieve
that is by making a new array called newar[] and make it include all
the indexes of ar[], except without -2."
This is a very inefficient way to approach this problem. You'll have to do 3 passes, Once to find to smallest indexed element, another pass to remove the element (this is an array so removing an element will require a full pass), and another one to find smallest one again.
You should just do a single pass algorithm and keep track of the smallest two integers,
or even better use a tree for efficiency. Here are the best answers of this problem:
Find the 2nd largest element in an array with minimum number of comparisons
Algorithm: Find index of 2nd smallest element from an unknown array
UPDATE: Here is the algorithm with OP's requirements,
3 passes, and no external libraries:
public static int Second_Tiny() {
int[] ar = {19, 1, 17, 17, -2};
//1st pass - find the smallest item on original array
int i;
int z = ar[0];
for (i = 1; i < ar.length; i++) {
if (z >ar[i]){
z=ar[i];
}
}
//2nd pass copy all items except smallest one to 2nd array
int[] ar2 = new int[ar.length-1];
int curIndex = 0;
for (i=0; i<ar.length; i++) {
if (ar[i]==z)
continue;
ar2[curIndex++] = ar[i];
}
//3rd pass - find the smallest item again
z = ar2[0];
for (i = 1; i < ar2.length; i++) {
if (z >ar2[i]){
z=ar2[i];
}
}
return z;
}
This grabs the index of the element specified in variable z and then sets a second array to the first array minus that one element.
Essentially this gives ar2 = ar1 minus element z
public static int Second_Tiny() {
int[] ar = {19, 1, 17, 17, -2};
int[] ar2;
int i;
int z = ar[0];
int x = 0;
for (i = 1; i < ar.length; i++) {
if (z >ar[i]){
z=ar[i];
x=i;
}
}
ar2 = ArrayUtils.remove(ar, x);
return(z);
}

Removing duplicates from array without using Util classes

Please read the question before marking it as duplicate
I have written following code to remove duplicates from array without using Util classes but now I am stuck
public class RemoveDups{
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45, };
int temp;
for (int i : a) {
for (int j = 0; j < a.length - 1; j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
a = removeDups(a);
for (int i : a) {
System.out.println(i);
}
}
private static int[] removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
}
}
return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
and now the output is
1
2
3
4
5
6
45
52
0
0
0
0
0
0
0
0
0
0
Here my problem is
My code is not working in case of 0s
I am not able to understand how sorting an array can reduce time of execution
Is there any way to remove elements from array without using Util classes I know one way to remove convert array into list and then remove but for that also we need Util classes is there any way to implement by myself.
Since the numbers you deal with are limited to a small range you can remove duplicates by a simple "counting sort": mark the numbers you have found in a set-like data structure and then go over the data structure. An array of boolean works just fine, for less memory usage you could create a basic bitset or hash table. If n is the number of elements in the array and m is the size of the range, this algorithm will have O(n+m) complexity.
private static int[] removeDups(int[] a, int maxA) {
boolean[] present = new boolean[maxA+1];
int countUnique = 0;
for (int i : a) {
if (!present[i]) {
countUnique++;
present[i] = true;
}
}
int[] result = new int[countUnique];
int j = 0;
for (int i=0; i<present.length; i++) {
if (present[i]) result[j++] = i;
}
return result;
}
I am not able to understand how sorting an array can reduce time of execution
In a sorted array you can detect duplicates in a single scan, taking O(n) time. Since sorting is faster than checking each pair - O(n log n) compared to O(n²) time complexity - it would be faster to sort the array instead of using the naive algorithm.
As you are making the result array of the same length as array a
so even if you put only unique items in it, rest of the blank items will have the duplicate values in them which is 0 for int array.
Sorting will not help you much, as you code is searching the whole array again and again for the duplicates. You need to change your logic for it.
You can put some negative value like -1 for all the array items first in result array and then you can easily create a new result array say finalResult array from it by removing all the negative values from it, It will also help you to remove all the zeroes.
In java , arrays are of fixed length. Once created, their size can't be changed.
So you created an array of size18.
Then after you applied your logic , some elements got deleted. But array size won't change. So even though there are only 8 elements after the duplicate removal, the rest 10 elements will be auto-filled with 0 to keep the size at 18.
Solution ?
Store the new list in another array whose size is 8 ( or whatever, calculate how big the new array should be)
Keep a new variable to point to the end of the last valid element, in this case the index of 52. Mind you the array will still have the 0 values, you just won't use them.
I am not able to understand how sorting an array can reduce time of execution
What ? You sort an array if you need it to be sorted. Nothing else. Some algorithm may require the array to be sorted or may work better if the array is sorted. Depends on where you are using the array. In your case, the sorting will not help.
As for your final question , you can definitely implement your own duplicate removal by searching if an element exists more than once and then deleting all the duplicates.
My code is not working in case of 0
There were no zeroes to begin with in your array. But because its an int[], after the duplicates are removed the remaining of the indexes are filled with 0. That's why you can see a lot of zeroes in your array. To get rid of those 0s, you need to create another array with a lesser size(size should be equal to the no. of unique numbers you've in your array, excluding 0).
If you can sort your array(I see that its already sorted), then you could either bring all the zeroes to the front or push them to the last. Based on that, you can iterate the array and get the index from where the actual values start in the array. And, then you could use Arrays.copyOfRange(array, from, to) to create a copy of the array only with the required elements.
try this
package naveed.workingfiles;
public class RemoveDups {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45, };
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i=0;i<count;i++) {
System.out.println(result[i]);
}
// return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
public class RemoveDups {
public static void main(String[] args) {
int[] a = { 1, 2, 0, 3, 1,0, 3, 6, 2};
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
boolean zeroExist = false;
for (int i : a) {
if(i==0 && !zeroExist){
result[j++] = i;
zeroExist = true;
count++;
}
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i=0;i<count;i++) {
System.out.println(result[i]);
}
// return result;
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}
// It works even Array contains 'Zero'
class Lab2 {
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 3, 1, 4, 52, 1, 45 };
removeDups(a);
}
private static void removeDups(int[] a) {
int[] result = new int[a.length];
int j = 0;
int count = 0;
for (int i : a) {
if (!isExist(result, i)) {
result[j++] = i;
count++;
}
}
System.out.println(count + "_____________");
for (int i = 0; i < count; i++) {
System.out.println(result[i]);
}
}
private static boolean isExist(int[] result, int i) {
for (int j : result) {
if (j == i) {
return true;
}
}
return false;
}
}

HeapSort theory?

I am not using HeapSort to sort an array that is already filled, but am using HeapSort as the array is filled.
For a heap where the smallest values are at the top, my understanding was that when you insert a new value to the heap you checked the parent node to see if the new child is larger. If it is you do nothing, if it isn't you check and swap as need up the tree?
Is this not right because my implementation of it is not working at all:
public class HeapSort{
static int[] numbers = new int[] { 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
static int[] array = new int[16];
public static void main(String[] args) {
for (int i = 1; i < 15; i++) {
array[i] = numbers[i];
if (i > 1)
sort(i);
}
for (int i = 1; i < 15; i++) {
System.out.println(array[i]);
}
}
public static void sort(int i) {
int parentLocation = i / 2;
int childLocation = i;
int parentValue = array[parentLocation];
int childValue = array[childLocation];
if(parentValue > childValue){
array[parentLocation] = childValue;
array[childLocation] = parentValue;
}
if(parentLocation != 1){
sort(parentLocation);
}
}
}
TIA
If its anyhelp this is the output when I give it 1-15 backwards:
2
6
3
9
7
5
4
15
12
13
8
14
10
11
But you all seem as stumped as I am!
It looks like your not sorting the entire array. Say that you have 10 fields correctly sorted and you insert number. So you have
-, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11 and insert 10 (should go second last and the - is cause you never put anything there)
Now your algorithm compares parentLocation 5 (11/2) and childLocation 11 right? Well, 5 is smaller than 11 so nothing is swapped. Then you continue to sort again with input 5.
This time you compare parentLocation 2 (5/2) and childLocation 5. 2 is smaller than 5, still not change.
Until done. But you never test to see if 10 and 11 is in the correct order at all, you start half way down.
Easiest fix is to change your two iterations to
for (int i = 1; i < numbers.length; i++) {...}
...
for (int i = 1; i < array.length; i++) {...}
As your missing the end positions in your current code.
Then change the first line in sort() to
int parentLocation = i - 1;
That way your recursive check checks the entire array.
But this is regular sorting, nothing heapy about it :)
Added complete new solution :)
I'm sure this is not the optimal solution but it's easy to follow. I've replaced the target heap with an ArrayList to be able to shrink it easy.
package se.wederbrand.stackoverflow;
import java.util.ArrayList;
public class HeapSort {
static int[] numbers = new int[]{0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
static ArrayList<Integer> heap = new ArrayList<Integer>();
public static void main(String[] args) {
// add 0 at the first position
heap.add(0);
for (int i = 1; i < numbers.length; i++) {
heap.add(numbers[i]);
if (i > 1) {
reheapifyBottomUp(i);
}
}
while (heap.size() > 1) {
System.out.println(removeFirstFromHeap());
}
}
private static int removeFirstFromHeap() {
// the value at index 1 should be returned
int returnValue = heap.get(1);
// the last node is replacing the removed one
if (heap.size() > 2) {
heap.set(1, heap.remove(heap.size() - 1));
reheapifyTopDown(1);
}
else {
heap.remove(1);
}
return returnValue;
}
public static void reheapifyBottomUp(int childLocation) {
int parentLocation = childLocation / 2;
int parentValue = heap.get(parentLocation);
int childValue = heap.get(childLocation);
if (parentValue > childValue) {
heap.set(parentLocation, childValue);
heap.set(childLocation, parentValue);
}
if (parentLocation != 1) {
reheapifyBottomUp(parentLocation);
}
}
public static void reheapifyTopDown(int parentLocation) {
int childLocation1 = parentLocation * 2;
int childLocation2 = childLocation1 + 1;
int parentValue = heap.get(parentLocation);
int childValue1 = Integer.MAX_VALUE;
if (heap.size() > childLocation1) {
childValue1 = heap.get(childLocation1);
}
int childValue2 = Integer.MAX_VALUE;
if (heap.size() > childLocation2) {
childValue2 = heap.get(childLocation2);
}
if (childValue1 <= childValue2 && parentValue > childValue1) {
// swap them and continue down
heap.set(parentLocation, childValue1);
heap.set(childLocation1, parentValue);
reheapifyTopDown(childLocation1);
}
else if (childValue2 < childValue1 && parentValue > childValue2) {
// swap them and continue down
heap.set(parentLocation, childValue2);
heap.set(childLocation2, parentValue);
reheapifyTopDown(childLocation2);
}
}
}
All you have done here is add a bunch of numbers to a heap (which looks correct at first glance). The array contains values in a heap -- not a sorted list. To get the sorted list out, in heap sort, you need to keep popping the smallest element and re-heaping. You're missing this step; you're just printing out the final heap before you start that process.
Your sort method should be renamed as heapify(). Your current sort() method is just re-arranging the heap.
A min/max heap is never sorted, and hence you can never traverse it the way you can traverse Binary Search Tree. You will have to implement something like removeMin() which will remove the topmost element from the heap and the sort the remaining heap.

Categories