Java min heap decrease array size after removing element - java

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.

Related

How I could find the maxim value of an array with recursive without having an index?

I have that method valorMaxim([1, 5, 252, 24, 7, 82, 3]) returns 252.
I don't know how to do it. I have been thinking if I could decrease the array length.
public static int valorMaxim(int arr[]){
int max;
if(arr.length==1)
return arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i] < arr[i+1]) {
max=arr[i+1];
return arr[i+1];
}
}
return valorMaxim(arr);
//Retorna el valor màxim en un array no buit d’enters.
}
I modified the accepted answer to Finding Max value in an array using recursion.
As you suggested (i.e. decrease the array length with each recursive method invocation), I create a copy of the method parameter whose length is one less than the parameter and remove the first element. Then I recursively call the method with the array copy.
public class Main {
public static int valorMaxim(int arr[]){
if (arr.length == 1) {
return arr[0];
}
else {
int[] tmp = new int[arr.length - 1];
System.arraycopy(arr, 1, tmp, 0, tmp.length);
return Math.max(arr[0], valorMaxim(tmp));
}
}
public static void main(String[] args) {
System.out.println(valorMaxim(new int[]{1, 5, 252, 24, 7, 82, 3}));
}
}
Basically, the recursive idea is:
If the array has length 1, return the only element;
Otherwise, split the array into x the first element, and xs the rest;
Find the maximum element within xs, compare it to x and yield the greater.
There are two ways to achieve such a "split":
Create a new copy of part of the array for xs
You can either use System.arraycopy (see answer by #Abra) or Arrays.copyOfRange, which is simpler:
int x = arr[0];
int[] xs = Arrays.copyOfRange(arr, 1, arr.length);
And now we lookup the maximum element within xs (which is valorMaxim(xs)), and compare it to x as the final result:
return Math.max(x, valorMaxim(xs));
Put everything together, and don't forget to add a length checker:
public static int valorMaxim(int arr[])
{
if (arr.length == 1) return arr[0];
int x = arr[0];
int[] xs = Arrays.copyOfRange(arr, 1, arr.length);
return Math.max(x, valorMaxim(xs));
}
And that's it! Since we have the length checker in the first place,
we can safely make sure xs would never be empty, and hence valorMaxim(xs) would
never result in ArrayIndexOutOfBoundsException.
Set a boundary for the array
You may have found that copying a new array at each time could be time- and memory-consuming.
Instead of creating a physical copy for xs, we can conceptualise the idea
and use a bounded array instead. We would need to define a helper method to do so:
private static int findMaxBound(int arr[], int startFrom)
{
// does "xs" have length 1?
if (startFrom == arr.length - 1) return arr[startFrom];
int x = arr[startFrom];
int maxInXs = findMaxBound(arr, startFrom + 1);
return Math.max(x, maxInXs);
}
And then we can define valorMaxim as
public static int valorMaxim(int arr[])
{
return findMaxBound(arr, 0);
}
In the end, we did not create any new copies of arr
but uses different ranges of itself and treat them as xs throughout the process.

Find the sum of custom number of elements in an array of Integers

I was interviewing for one of the big techs where I was asked a programming question in the problem solving round. The question is very similar to the Two Sum problem in Leet Code except for one tricky constraint. The question goes like this :
Given an array of integers nums, an integer target and an integer limit, return exactly one set of elements that counts up to the given limit and adds up to the given target.
Input: nums = [2,7,11,15], target = 20, limit = 3
Output: [2, 7, 11]
Explanation : The target is 20 and the limit is 3, so, we will have to find 3 numbers from the array that add up to 20.
I wasn't able to solve this during the interview and have been searching for a solution ever since.
The brute force approach is to run as many loops as the limit, which is not viable, considering the fact that the limit may be <= 10,000
And another is to extract sub-arrays of length = limit, run through each and every one, add their elements and return a sub-array that adds up to Target.
But, I am sure there must be a more efficient approach to solve this.
Any ideas?
Edit :
The output that we return may be random and not necessarily contiguous.
The limit has to be met and the number of elements that we return must be equal to the limit.
There is no limit on the size of the array
Use Stack (recursively) to find the array elements which will sum to the desired target within the required array elements limit. Doing it this way will actually find all combinations but only those which use fall on the elements limit are placed into a List.
Please read the comments in code. Delete them later if you like. Here is a runnable to demonstrate this process:
package sumtargetlimit_demo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Stack;
public class SumTargetLimit_Demo {
// The desired Target Sum
private int targetSum = 20;
/* The max allowable array elements to use in order to acquire
the desired Target Sum. */
private int numbersLimit = 3;
// A Stack to hold the Array elements which sum to the desired Target Sum.
private Stack<Integer> stack = new Stack<>();
// Store the summation of current elements held in stack.
private int sumInStack = 0;
/* A List Interface of Integer[] array to hold all the
combinations of array elements which sum to target. */
private List<Integer[]> combinationsList = new ArrayList<>();
public static void main(String[] args) {
// Demo started this way to avoid the need for statics.
new SumTargetLimit_Demo().startDemo(args);
}
private void startDemo(String[] args) {
// The int array to work against.
int[] intData = {2, 7, 11, 15};
/* See which array elements can acquire the desired
Target Sum with the maximum number of array elements
specified in the numbersLimit member variable. */
getSummations(intData, 0, intData.length);
// Display the found results to Console window...
if (combinationsList.isEmpty()) {
System.err.println("No integer elements within the supplied Array will");
System.err.println("provide a Taget Sum of " + targetSum + " with a maximum number");
System.err.println("limit of " + numbersLimit + ".");
}
else {
for (Integer[] intArray : combinationsList) {
System.out.println(Arrays.toString(intArray).replaceAll("[\\[\\]]", ""));
}
}
}
// Note: This method is recursive...
public void getSummations(int[] data, int startIndex, int endIndex) {
/* Check to see if the sum of array elements stored in the
Stack is equal to the desired Target Sum. If it is then
convert the array elements in the Stack to an Integer[]
Array and add it to the conmbinationsList List. */
if (sumInStack == targetSum) {
if (stack.size() <= numbersLimit) {
combinationsList.add(stack.toArray(new Integer[stack.size()]));
}
}
for (int currIndex = startIndex; currIndex < endIndex; currIndex++) {
if (sumInStack + data[currIndex] <= targetSum) {
stack.push(data[currIndex]);
sumInStack += data[currIndex];
// Make the currentIndex +1, and then use recursion to carry on.
getSummations(data, currIndex + 1, endIndex);
sumInStack -= stack.pop();
}
}
}
}
Try a much larger int[] array and play with the Target Sum and Number Limit to see how things work.
Another way, to look at this problem is through the eyes of dynamic programming. For any element in the array, there are two cases:
It will be a part of the elements, which make up the sum, in that case, we recursively, find the elements that make the remaining sum, with limit - 1.
It will not be part of the elements, which make up the sum, in this case, we look for the target, in the remaining part of the array.
Here, is the sample following the above logic:
import java.util.*;
class HelloWorld {
static Map<Integer, List<Integer>> cache = new HashMap<>();
public static void main(String[] args) {
int[] array = {9, 2, 15, 11, 7, 23, 54, 50, 12};
int limit = 4;
int target = 35;
// This is to optimize the search for element in case the limit is 1
Arrays.sort(array);
List<Integer> subarray = getElementsWithSumEqualToTarget(array, 0, limit, target);
System.out.println(subarray);
}
static List<Integer> getElementsWithSumEqualToTarget(int[] array, int startingIndex, int limit, int target) {
// If limit is 0, or we have reached the end of the array then sum doesn't exists.
if(limit == 0 || startingIndex >= array.length) {
return null;
} else if(limit == 1) {
// For limit 1, we can do a simple binary search, or linear search in that case Arrays.sort can be removed
int index = Arrays.binarySearch(array, startingIndex, array.length - 1, target);
if(index < 0) {
return null;
}
ArrayList<Integer> list = new ArrayList();
list.add(target);
return list;
} else if (cache.containsKey(target)) {
// If for a given sum, the subarray of elements, is already present, we can return it from the cache.(Memoization)
return cache.get(target);
}
// Case 1: The current element will be part of the sum.
List<Integer> subarray = getElementsWithSumEqualToTarget(array, startingIndex + 1, limit - 1, target - array[startingIndex]);
if(subarray != null) {
subarray.add(array[startingIndex]);
// Add target and subarray to the cache
cache.put(target, subarray);
return subarray;
}
// Case 2: Current element is not part of the sum
subarray = getElementsWithSumEqualToTarget(array, startingIndex + 1, limit, target);
if(subarray != null) {
cache.put(target, subarray);
}
return subarray;
}
}
Please try it out on large datasets, and see how it works. Hopefully, it helps.

How to get a collection of combinations of an Integer arrayList in Java

My goal is to find all possible combinations of items in an ArrayList with a fixed predefined length. For example, if my ArrayList is called arr and contains <1, 2, 3> then the desired output for the predefined size r = 2 will be:
<1,2>
<1,3>
<2,3>
Here is code I found which prints the desired output. My problem is that I need to define a return value type ArrayList which holds the outputs from the method. Besides, my input type is also an ArrayList<Integer>, instead of an Array, which has made it more complicated for me because then I first will need to convert the values to the primitive type int.
import java.io.*;
class Permutation {
/* arr[] ---> Input Array
data[] ---> Temporary array to store current combination
start & end ---> Staring and Ending indexes in arr[]
index ---> Current index in data[]
r ---> Size of a combination to be printed */
static void combinationUtil(int arr[], int data[], int start,
int end, int index, int r)
{
// Current combination is ready to be printed, print it
if (index == r)
{
for (int j=0; j<r; j++)
System.out.print(data[j]+" ");
System.out.println("");
return;
}
// replace index with all possible elements. The condition
// "end-i+1 >= r-index" makes sure that including one element
// at index will make a combination with remaining elements
// at remaining positions
for (int i=start; i<=end && end-i+1 >= r-index; i++)
{
data[index] = arr[i];
combinationUtil(arr, data, i+1, end, index+1, r);
}
}
// The main function that prints all combinations of size r
// in arr[] of size n. This function mainly uses combinationUtil()
static void printCombination(int arr[], int n, int r)
{
// A temporary array to store all combination one by one
int data[]=new int[r];
// Print all combination using temprary array 'data[]'
combinationUtil(arr, data, 0, n-1, 0, r);
}
/*Driver function to check for above function*/
public static void main (String[] args) {
int arr[] = {1, 2, 3, 4, 5};
int r = 3;
int n = arr.length;
printCombination(arr, n, r);
}
}
/* This code is contributed by Devesh Agrawal */
ArrayList is backed up by an array internally so translating the current array based implementation to ArrayList should be reasonable. In arrays you use the [] operator to index an element in the array, and the parallel operations using ArrayList are get and set. Also you might want to read on Autoboxing and Unboxing. A possible implementation using Lists:
static void combinationUtil(List<Integer> list, List<Integer> data, int start, int end, int index, int r) {
// Current combination is ready to be printed, print it
if (index == r) {
for (int j = 0; j < r; j++)
System.out.print(data.get(j) + " ");
System.out.println("");
return;
}
// replace index with all possible elements. The condition
// "end-i+1 >= r-index" makes sure that including one element
// at index will make a combination with remaining elements
// at remaining positions
for (int i = start; i <= end && end - i + 1 >= r - index; i++) {
data.set(index, list.get(i));
combinationUtil(list, data, i + 1, end, index + 1, r);
}
}
// The main function that prints all combinations of size r
// in list of size n. This function mainly uses combinationUtil()
static void printCombination(List<Integer> list, int n, int r) {
// A temporary array to store all combination one by one
List<Integer> data = new ArrayList<>(Collections.nCopies(r, 0));
// Print all combination using temporary array 'data'
combinationUtil(list, data, 0, n - 1, 0, r);
}
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
int r = 3;
int n = list.size();
printCombination(list, n, r);
}

Rearrange an array in minimum and maximum java

Given an array of ints, I want to rearrange it alternately i.e. first element should be minimum, second should be maximum, third second-minimum, fourth second-maximum and so on...
I'm completely lost here...
Another method that doesn't require the space of three separate arrays but isn't as complex as reordering in place would be to sort the original array and then create a single new array. Then start iterating with a pointer to the current i-th index of the new array and pointers starting at the 0-th index and the last index of the sorted array.
public class Foo {
public static void main(String[] args) {
// Take your original array
int[] arr = { 1, 4, 5, 10, 6, 8, 3, 9 };
// Use the Arrays sort method to sort it into ascending order (note this mutates the array instance)
Arrays.sort(arr);
// Create a new array of the same length
int[] minMaxSorted = new int[arr.length];
// Iterate through the array (from the left and right at the same time)
for (int i = 0, min = 0, max = arr.length - 1; i < arr.length; i += 2, min++, max--) {
// the next minimum goes into minMaxSorted[i]
minMaxSorted[i] = arr[min];
// the next maximum goes into minMaxSorted[i + 1] ... but
// guard against index out of bounds for odd number arrays
if (i + 1 < minMaxSorted.length) {
minMaxSorted[i + 1] = arr[max];
}
}
System.out.println(Arrays.toString(minMaxSorted));
}
}
Hint:
Create two new arrays, 1st is sorted in assenting order and other is in descending order. Than select 1st element from 2nd array and 1st element from 1st array, repeat this selection until you reach half of both 1st and second array. and you will get your desired array.
Hope this will help you.
The approach in #Kaushal28's answer is the best approach for a beginner. It requires more space (2 extra copies of the array) but it is easy to understand and code.
An advanced programmer might consider sorting the array once, and then rearranging the elements. It should work, but the logic is complicated.
Hint: have you ever played "Clock Patience"?
This solution is based on Aaron Davis solution. I tried to make the looping easier to follow:
public class AltSort {
//list of array elements that were sorted
static Set<Integer> indexSorted = new HashSet<Integer>();
public static void main (String[] args) throws java.lang.Exception
{
//test case
int[] array = new int[]{7,22,4,67,5,11,-9,23,48, 3, 73, 1, 10};
System.out.println(Arrays.toString(altSort(array)));
//test case
array = new int[]{ 1, 4, 5, 10, 6, 8, 3, 9 };
System.out.println(Arrays.toString(altSort(array)));
}
private static int[] altSort(int[] array) {
if((array == null) || (array.length == 0)) {
System.err.println("Empty or null array can not be sorted.");
}
Arrays.sort(array);
//returned array
int[] sortedArray = new int[array.length];
int firstIndex = 0, lastIndex = array.length-1;
for (int i = 0; i < array.length; i++) {
if((i%2) == 0) { //even indices
sortedArray[i] = array[firstIndex++];
}
else {
sortedArray[i] = array[lastIndex --];
}
}
return sortedArray;
}
}
Here is another alternative: monitor the indices that have been sorted, and search the rest for the next min / max:
import java.util.Arrays;
import java.util.Set;
/**
* Demonstrates an option for sorting an int[] array as requested,
* by keeping a list of the array indices that has been sorted, and searching
* for the next min / max.
* This code is not optimal nor robust. It serves a demo for this option only.
*
*/
public class AltSort {
//list of array elements that were sorted
static Set<Integer> indexSorted ;
public static void main (String[] args) throws java.lang.Exception {
//test case
int[] array = new int[]{7,22,4,67,5,11,-9,23,48, 3, 73, 1, 10};
System.out.println(Arrays.toString(altSort2(array)));
//test case
array = new int[]{ 1, 4, 5, 10, 6, 8, 3, 9 };
System.out.println(Arrays.toString(altSort2(array)));
}
private static int[] altSort2(int[] array) {
if((array == null) || (array.length == 0)) {
System.err.println("Empty or null array can not be sorted.");
}
//returned array
int[] sortedArray = new int[array.length];
//flag indicating wether to look for min or max
boolean lookForMin = true;
int index = 0;
while(index < array.length) {
if(lookForMin) {
sortedArray[index] = lookForArrayMin(array);
}else {
sortedArray[index] = lookForArrayMax(array);
}
index++;
//alternate look for min / look for max
lookForMin = ! lookForMin;
}
return sortedArray;
}
private static int lookForArrayMin(int[] array) {
int minValue = Integer.MAX_VALUE;
int minValueIndex = 0;
for( int i =0; i< array.length; i++ ){
//if array[i] is min and was not sorted before, keep it as min
if( (array[i]< minValue) && ! indexSorted.contains(i) ) {
minValue = array[i]; //keep min
minValueIndex = i; //keep min index
}
}
//add the index to the list of sorted indices
indexSorted.add(minValueIndex);
return minValue;
}
private static int lookForArrayMax(int[] array) {
int maxValue = Integer.MIN_VALUE; //max value
int maxValueIndex = 0; //index of max value
for( int i =0; i< array.length; i++ ){
//if array[i] is max and was not sorted before, keep it as max
if( (array[i] > maxValue) && ! indexSorted.contains(i)) {
maxValue = array[i]; //keep max
maxValueIndex = i; //keep max index
}
}
//add the index to the list of sorted indices
indexSorted.add(maxValueIndex);
return maxValue;
}
}

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

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
}

Categories