How to add and restore a heap? - java

In a problem, we were supposed to remove four (4) elements from this maxHeap (see image below), and every time an element was removed, the heap property had to be restored. The list with the remaining heap elements had to be in level-order.
public class HeapSort {
public static void heapify(int node[], int n, int i) {
int largest = i, // Initialize largest as root
l = 2 * i + 1, // Left = 2*i + 1
r = 2 * i + 2; // Right = 2*i + 2
if (l < n && node[l] > node[largest]) {
largest = l; // If left child is larger than root (n = size of heap)
}
if (r < n && node[r] > node[largest]) {
largest = r; // If right child is larger than largest
}
if (largest != i) {
int swap = node[i];
node[i] = node[largest]; // If largest is not root
node[largest] = swap;
heapify(node, n, largest); // Recursively heapify the affected sub-tree
}
}
/**
* Deletes the root from the Heap.
*/
public static int deleteRoot(int node[], int n) {
int lastElement = node[n - 1]; // Get the last element
node[0] = lastElement; // Replace root with first element
n -= 1; // Decrease size of heap by 1
heapify(node, n, 0); // Heapify the root node
return n; // Return new size of Heap
}
/**
* A utility function to print array of size N
*/
public static void printArray(int array[], int n) {
System.out.print("_ ");
for (int i = 0; i < n; ++i) {
System.out.print(array[i] + " ");
}
}
public static void main(String args[]) {
// Insert values representing the Heap.
int node[] = {65, 55, 60, 45, 25, 40, 50, 10, 35, 15, 20, 30};
int n = node.length,
removes = 4; // Insert the number of elements you want to delete (e.g.: 4).
for(int i = 0; i < removes; i++) {
n = deleteRoot(node, n);
}
printArray(node, n);
}}
This code gave me this answer, which is correct according to my quiz:
_ 45 35 40 20 25 15 30 10
My problem is when adding to the heap, with the following challenge: Build a minHeap by adding the following seven elements in the order in which they are listed to the heap above. Every time an element is added, the heap property needs to be restored.
Numbers to be added to the heap:
30 75 35 15 70 20 10
When you are done, list the elements in level-order. Include a leading underscore to indicate that the element on index 0 is not used.
Disclaimer: this, as mention, WAS a quiz and therefore you wouldn't be doing my assignment. I am just curious. Maybe I should use PriorityQueue... I've been trying, but I am not getting anywhere.

As you have already implemented, a deletion works as follows:
Delete the last node and put its value in the root node
Sift down the root's value until the heap property is restored (implemented in heapify)
Insertion works in the other direction:
Append the node with the new value at the end
Sift up that value until the heap property is restored.

Related

Implementing a heap: becomes inaccurate after one sift

I am currently trying to write a program that takes an array and makes it into a heap.
I am trying to implement a siftDown method that will take the elements of the array and make them into a heap but i am just not getting the correct output i want and im not sure why:
public void makeHeap(int[] arr)
{
for(int i = 0; i <= arr.length; i++)//for each element in the array, we we check its children and sift it down
{
siftDown(arr, i);
}
}
//insert a new root in the correct position. Byu comparing the top element and swapping it with its largest child.
public void siftDown(int[]heap, int i)
{
int c = i * 2; //grab the children of the current index we are at.
if(c == 0) // 0*2 is 0 so we make it 1 so it will register the first nodes parents
{
c+=1;
}
if(c >= heap.length || c+1 >= heap.length) // so we dont go off the end of the array
{
return;
}
if(heap[c] < heap[c + 1]) //Is child 1 less than child 2?
{
c += 1; //if it is we want c to be the greater child to eventually move upwards
}
if(heap[i] < heap[c])//If the parent we have just gotten is smaller than the child defined last loop, then we swap the two. We then call sift down again to compare child and parent.
{
heap = swap(heap,i,c);//swap the values
siftDown(heap, c);//call again to compare the new root with its children.
}
}
Here is my swap method:
public int[] swap(int[]heap, int i, int c)
{
//capture the two values in variables
int ele1 = heap[i];
int ele2 = heap[c];
heap[i] = ele2;//change heap i to heap c
heap[c] = ele1;//change heap c to heap i
return heap;
}
The starting numbers are: 4,7,9,6,3,1,5
. The output i want to get is 9,7,5,6,3,1,4 but i seem to only be able to get 9,7,4,6,3,1,5. It seems once 4 gets sifted down once after being replaced by 9, the algorithm goes out of wack and it believes that 3 and 1 are its children when 1,5 should be.
Thank you or your help!
int c = i * 2; //grab the children of the current index we are at.
if(c == 0) // 0*2 is 0 so we make it 1 so it will register the first nodes parents
{
c+=1;
}
This looks wrong to me.
The heap indices for children should be a general formula that works for all cases.
Given parentIdx in 0-based array,
leftChildIdx = parentIdx * 2 + 1
rightChildIdx = parentIdx * 2 + 2
This means children of 0 are 1 and 2, children of 1 are 3 and 4, children of 2 are 5 and 6, etc. It works.
Your code places children of 1 at 2 and 3, which is clearly wrong.

using 'extract' method to iteratively remove smallest element from min heap and copy to designated arrayList as a method of obtaining a sorted list

I have a program that reads in a text file and creates a number of nodes elements that can be used to build into a MIN heap.
What I'm struggling with is, after the Min heap has been correctly built, I'm supposed to sort the elements by using an 'extract' method to remove the smallest element at the root and adding it to a separate ArrayList intended to contain the elements in sorted order.
Of course we are supposed to extract one element at a time and add it to our new arraylist and then, remove that element from the heap of remaining nodes, so that the heap keeps decreasing by one element and the sorted arraylist keeps increasing by one element until there are no remaining elements in the heap.
I believe the problem is that after extracting the root element of the min heap, the root element itself isn't erased, it seems to remain in the heap even though my extract method is supposed to overwrite the removed root element by replacing it with the last item in the heap and then decrementing the heap size and re-applying the 'heapify' method to restore the heap property.
My code is fairly simple, the main method is long but the significant part is as follows:
g = new Graph();
readGraphInfo( g );
DelivB dB = new DelivB(inputFile, g);
int numElements = g.getNodeList().size();
ArrayList<Node> ordered_nodeList = new ArrayList<Node>(15);
ArrayList<Node> sorted_nodeList = new ArrayList<Node>(15);
h = new Heap(ordered_nodeList, g);
for (int i = 0; i < numElements; i++)
{
ordered_nodeList.add(i, g.getNodeList().get(i));
h.Build_min_Heap(ordered_nodeList);
System.out.println("Heap: \n");
System.out.println("\n**********************" + "\nProg 340 line 147" +h.heapClass_toString(ordered_nodeList));
//System.out.println("the " + i + "th item added at index " + i + " is: " + ordered_nodeList.get(i).getAbbrev());
}
for (int j = 0; j < numElements; j++)
{
sorted_nodeList.add(j, h.heap_Extract(ordered_nodeList));
System.out.println("the "+j+"th item added to SORTED node list is: "+sorted_nodeList.get(j).getAbbrev()+ " "+ sorted_nodeList.get(j).getVal());
//h.heap_Sort(ordered_nodeList);
System.out.println("\nthe 0th remaining element in ordered node list is: " + ordered_nodeList.get(0).getVal());
h.Build_min_Heap(ordered_nodeList);
}
for (Node n : sorted_nodeList)
{
System.out.println("sorted node list after extract method*****************\n");
System.out.println(n.toString());
}
The output I keep getting is as follows:
the 0th remaining element in ordered node list is: 55
the 1th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 2th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 3th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 4th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
the 5th item added to SORTED node list is: F 55
the 0th remaining element in ordered node list is: 55
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
sorted node list after extract method*****************
F
My Heap class is as follows:
import java.util.*;
public class Heap
{
int heapSize;
ArrayList unordered_nodeList;
ArrayList ordered_nodeList;
Graph gr;
nodes
public Heap(ArrayList<Node> A, Graph g)
{
unordered_nodeList = g.getNodeList();
heapSize = unordered_nodeList.size();
ordered_nodeList = A;
gr = g;
}
public ArrayList getUnordered_nodeList() {
return unordered_nodeList;
}
public void setUnordered_nodeList(ArrayList unordered_nodeList) {
this.unordered_nodeList = unordered_nodeList;
}
public ArrayList getOrdered_nodeList() {
return ordered_nodeList;
}
public void setOrdered_nodeList(ArrayList ordered_nodeList) {
this.ordered_nodeList = ordered_nodeList;
}
public int getHeapSize() {
return heapSize;
}
public void setHeapSize(int heapSize) {
this.heapSize = heapSize;
}
//heap methods
public int Parent(ArrayList<Node> A, int i)
{
//if (i == 1)
//return (Integer)null;
if (i%2 != 0)
return i/2;
else
return (i-1)/2;
}
public int Left(ArrayList<Node> A, int i)
{
if (2*i < A.size()-1)
return (2*i)+1;
else
return i;
//return (Integer)null;
}
public int Right(ArrayList<Node> A, int i)
{
if ((2*i)+1 < A.size()-1)
return 2*i+2;
else
return i;
//return (Integer)null;
}
public void Heapify(ArrayList<Node> A, int i)
{
Node smallest;
Node temp;
int index;
int l = Left(A,i);
int r = Right(A,i);
if (l <= heapSize-1 && Integer.parseInt(A.get(l).getVal()) < Integer.parseInt(A.get(i).getVal()))
{
//left child is smaller
smallest = A.get(l);
index = l;
}
else
{
//parent node is smaller
smallest = A.get(i);
index = i;
}
if (r <= heapSize-2 && Integer.parseInt(A.get(r).getVal()) < Integer.parseInt(smallest.getVal()))
{
//right child is smaller
smallest = A.get(r);
index = r;
}
if (index != i)
{
//if the smallest element is not the parent node
//swap the smallest child with the parent
temp = A.get(i);
A.set(i, A.get(index));
A.set(index, temp);
//recursively call heapify method to check next parent/child relationship
Heapify(A, index);
//System.out.println(this.heapClass_toString(ordered_nodeList));
}
//System.out.println("\n**********************" + "\nHeapify line 123" + this.heapClass_toString(ordered_nodeList));
}
//method to construct min heap from unordered arraylist of nodes
public void Build_min_Heap(ArrayList<Node> A)
{
int i;
int heapSize = A.size();
for (i = (heapSize/2); i>=0; i--)
{
//System.out.println(gr.toString2() +"\n");
//System.out.println("build heap ********** line 138" +this.heapClass_toString(ordered_nodeList));
Heapify(A, i);
//System.out.print(gr.toString2()+"\n");
}
}
//method to sort in descending order, a min heap
public void heap_Sort(ArrayList<Node> A)
{
Node temp;
//Build_min_Heap(A);
while (A.size() > 0)
{
///System.out.println("\n******************************\n heap_sort line 180" +this.heapClass_toString(ordered_nodeList));
//for (int i = 0; i <= A.size()-1; i++)
for(int i = A.size()-1; i >= 1; i--)
{
//exchange a[0] with a[i]
temp = A.get(0);
A.set(0, A.get(i));
A.set(i, temp);
//System.out.println(this.heapClass_toString(ordered_nodeList));
//decrement heapSize
heapSize--;
//recursive heapify call
Heapify(A, 0);
System.out.println("\n******************************\n heap_sort line 203" +this.heapClass_toString(ordered_nodeList));
}
System.out.println("\n******************************\n heap_sort line 206" +this.heapClass_toString(ordered_nodeList));
Heapify(A, A.size()-1);
}
}
public Node heap_Extract(ArrayList<Node> A)
{
//Node min = null;
//if (heapSize>0)
//while (A.get(0) != null && heapSize > 0)
Node min = A.get(0);
//min = A.get(0);
while (heapSize>0)
{
min = A.get(0);
A.set(0, A.get(heapSize-1));
//decrement heapSize
heapSize--;
Heapify(A, 0);
}
return min;
}
//return min;
public String heapClass_toString(ArrayList A)
{
String s = "Graph g.\n";
if (A.size() > 0 )
{
for (int k = 0; k < A.size(); k++ )
{
//output string to print each node's mnemonic
String t = this.getOrdered_nodeList().get(k).toString();
s = s.concat(t);
}
}
return s;
}
}
One issue is the following loop in your heap_Extract() method:
while (heapSize>0)
{
min = A.get(0);
A.set(0, A.get(heapSize-1));
//decrement heapSize
heapSize--;
Heapify(A, 0);
}
This loop will run over and over again until your heap has nothing in it, and then the function will return the last node min was set to (which should be the largest element in the original heap, if Heapify is implemented correctly). Subsequent calls will see that heapSize == 0, skip the loop entirely, and immediately and return min, which will be set to A.get(0), which will still be the largest element in the original Heap. You should ensure that the code in the body of this loop only runs at most one time (i.e. it shouldn't be in a loop, but perhaps should be guarded by some other conditional branch statement) for each call of heap_Extract().

Why doesn't my search algorithm work for Project Euler 31?

Problem 31
In England the currency is made up of pound, £, and pence, p, and
there are eight coins in general circulation: 1p, 2p, 5p, 10p, 20p,
50p, £1 (100p) and £2 (200p). It is possible to make £2 in the
following way: 1×£1 + 1×50p + 2×20p + 1×5p + 1×2p + 3×1p How many
different ways can £2 be made using any number of coins?
static int[] nums = {200,100,50,20,10,5,2,1};
static int size = nums.length;
static HashMap<Integer,Integer> pivots = new HashMap<>();
public static int checkSum(HashMap<Integer,Integer> pivots){
int target = 200;
int sum = 0;
for(Integer key: pivots.keySet()){
int pivot = pivots.get(key);
sum += nums[pivot];
if(sum > target) return 1;
}
if(sum < target) return -1;
return 0;
}
public static void shift(HashMap<Integer,Integer> pivots, int pivot_node){
if(pivots.size() + nums[pivots.get(1)] == 201 && pivots.get(1) != 0){
int p_1_value = pivots.get(1); //this part checks whether the current node(which is the first node)
//has reached children of all 1.
//Which means it's time to shift the root node.
pivots.clear();
pivots.put(1 , p_1_value);
shift(pivots, 1);
return;
}
if(pivots.get(pivot_node) != size - 1) {
pivots.put(pivot_node, pivots.get(pivot_node) + 1);
}
else{
shift(pivots , pivot_node - 1);
}
}
public static void branch(HashMap<Integer,Integer> pivots){
pivots.put(pivots.size() + 1, pivots.get(pivots.size()));
}
public static int search(){
int bool = checkSum(pivots);
int n = 0;
int count = 0;
while(n < 25) {
count++;
if (bool == 0) {
n++; // if the sum is equal to 200, we shift the last
//pivot to the next lower number.
shift(pivots, pivots.size());
}else if (bool == -1) {
branch(pivots); //if the sum is less than 200, we make a new pivot with value of the last pivot.
}else if (bool == 1) {
shift(pivots, pivots.size()); //if the sum is greater than 200,
//we shift to the last pivot to the next lower number.
}
bool = checkSum(pivots);
}
return n;
}
public static void main(String[] args){
pivots.put(1,0);
int n = search();
System.out.print("\n\n------------\n\n"+ "n: " + n);
}
This is an algorithm that searches for combinations of a set that add up to a target. It's kind of like a depth first tree search without using a tree. Each pivot represents node on the "tree". The shift() method changes the value of the node to the next lower value. The branch() method creates a new node with the same value of the last node. The checkSum() method checks whether the sum of the pivots are <,= or > the target, 200.
The correct answer for the number of ways is supposed to be around 73000. But my algorithm only returns about 300 ways.
I have no idea why this happens because my algorithm should reach every single possible combination that equals 200.
This is a visualization of how my algorithm works:
Your search algorithm doesn't find all possible combinations of coins that make up £2 because you are only shifting the "last pivot" to the next lower number, when you should be considering the items before that last one too.
Your algorithm will find this combination:
100, 50, 20, 20, 5, 2, 2, 1
but not this:
100, 20, 20, 20, 10, 5, 2, 2, 1
The second combination does not have the value 50 in it, but your algorithm breaks down the coin values backwards to forwards only -i.e. it will never break down 50 until all the following "pivots" are 1. You can easily see that if you print your HashMap<Integer,Integer> pivots every time the counter n is incremented.
You could try to fix your code by amending it to shift() using not only the last pivot but all the distinct previous pivots too. However, doing so you will create a lot of duplicates, so you'll need to keep a list of the distinct found combinations.
Another way to solve problem 31 is by using Dynamic Programming. Dynamic programming is best when it comes to problems that can be broken down in smaller bits. For example the solution of the same problem but where
target = 2 can be used to solve the problem where target = 5, which can be used to solve the problem where target = 10 and so on.
Good luck!

Simple algorithm but running out of memory

Problem
A sequence of positive rational numbers is defined as follows:
An infinite full binary tree labeled by positive rational numbers is
defined by:
The label of the root is 1/1
The left child of label p/q is p/(p+q)
The right child of label p/q is (p+q)/q
The top of the tree is shown in the following figure:
The sequence is defined by doing a level order (breadth first)
traversal of the tree (indicated by the light dashed line). So that:
F(1)=1/1,F(2)=1/2,F(3)=2/1,F(4)=1/3,F(5)=3/2,F(6)=2/3,…
Write a program which finds the value of n for which F(n) is p/q for
inputs p and q.
Input
The first line of input contains a single integer P, (1≤P≤1000), which
is the number of data sets that follow. Each data set should be
processed identically and independently. Each data set consists of a
single line of input. It contains the data set number, K, a single
space, the numerator, p, a forward slash (/) and the denominator, q,
of the desired fraction.
Output
For each data set there is a single line of output. It contains the
data set number, K, followed by a single space which is then followed
by the value of n for which F(n) is p/q. Inputs will be chosen so n
will fit in a 32-bit integer.
Source to question
My approach
I create the heap and planned to iterate over it until I find the element(s) in question, but I ran out of memory so I'm pretty sure I'm supposed to do it without creating the heap at all?
Code
public ARationalSequenceTwo() {
Kattio io = new Kattio(System.in, System.out);
StringBuilder sb = new StringBuilder(10000);
int iter = io.getInt();
// create heap
int parent;
Node[] heap = new Node[Integer.MAX_VALUE];
int counter = 1;
heap[0] = new Node(1, 1);
while (counter < Integer.MAX_VALUE) {
parent = (counter - 1) / 2;
// left node
heap[counter++] = new Node(heap[parent].numerator, heap[parent].numerator + heap[parent].denominator);
// right node
heap[counter++] = new Node(heap[parent].numerator + heap[parent].denominator, heap[parent].denominator);
}
// find Node
int dataSet;
String word;
int numerator;
int denominator;
for (int i = 0; i < iter; i++) {
dataSet = io.getInt();
word = io.getWord();
numerator = Integer.parseInt(word.split("/")[0]);
denominator = Integer.parseInt(word.split("/")[1]);
for (int j = 0; j < Integer.MAX_VALUE; j++) {
Node node = heap[j];
if (node.numerator == numerator && node.denominator == denominator) {
sb.append(dataSet).append(" ").append(j).append("\n");
}
}
}
System.out.println(sb);
io.close();
}
let's consider node n = a/b. If n is a left child of its parent, then n = p/(p+q), where the parent is p/q. I.e.
p = a,
b = p + q
p = a,
q = b - a
If n is a right child of its parent, then n = (p+q)/q:
a = p + q
b = q
p = a - b =
q = b
so, given for example 3/5, is it a left child or a right child? If it was a left child, then it's parent would be 3/(5-3) = 3/2. For the right child, we would have (3-5)/5 = -2/5. As this would not be positive, clearly n is a left child.
So, generalizing:
given a rational n, we can find the path to the root as follows:
ArrayList lefts = new ArrayList<>();
while (nNum != nDen) {
if (nNum < nDen) {
//it's a left child
nDen = nDen - nNum;
lefts.add(true);
} else {
nNum = nNum - nDen;
lefts.add(false);
}
}
Now that we have the path in the array, how do we translate it in the final result? Let's observe that
if the value given was 1/1, then the array is empty, and we should return 1
Every time we go from level n to level n+1, we add 2^n to the result. For example, going from level 0 to level 1 we add 1 (the root). going from level 1 to level 2 we add all two nodes of level 1, which are 2, etc.
We're left with the last piece, which is adding the nodes to the left of the last node we have, the one corresponding to the input rational, plus one. How many node are on the left? if you try to label each arc going left with 0 and each arc going right with 1, you'll notice that the path spells in binary the number of nodes in the last level. For example, 3/5 is the left child of 3/2. the array will be populated with false, true, false. in binary, 010. The final result is 2^0 + 2^1 + 2^2 + 010 + 1 = 1 + 2 + 4 + 2 + 1 = 10
Finally, note that sum(2^i) is 2^(i+1) - 1. so, we can finally write the code for the second part:
int s = (1 << lefts.size()) - 1) // 2^(i+1) - 1
int k = 0
for (int i = lefts.size() - 1; i >= 0; i---) {
if (lefts.get(i)) {
k += 1 << i;
}
}
return s + k + 1;
A full program taking in input num and den:
import java.util.ArrayList;
public class Z {
public static int func(int num, int den) {
ArrayList<Boolean> lefts = new ArrayList<>();
while (num != den) {
if (num < den) {
//it's a left child
den = den - num;
lefts.add(true);
} else {
num = num - den;
lefts.add(false);
}
}
int s = (1 << lefts.size()) - 1; // 2^(i+1) - 1
int k = 0;
for (int i = lefts.size() - 1; i >= 0; i--) {
if (!lefts.get(i)) {
k += 1 << i;
}
}
return s + k + 1;
}
public static void main(String[] args) {
System.out.println(func(Integer.parseInt(args[0]),
Integer.parseInt(args[1])));
}
}
Given a number p/q you can see whether it's a left or right child of its parent by considering whether p > q or p < q. And one can repeat that process all the way up the tree back to the root.
That gives a relatively simple recursive solution. In pseudocode:
T(p, q) =
1 if p == q == 1
2 * T(p, q-p) if p < q
2 * T(p-q, q) + 1 if p > q
This in theory could cause a stack overflow, because it runs in O(p+q) time and space. For example, T(1000000, 1) will require 1 million recursive calls. But it's given in the question that T(p, q) < 2**31, so the depth of the tree can be at most 32, and this solution works just fine.

Reduced time complexity of inner loop: Find count of elements greater than current element in the first loop and store that in solved array

I want to reduce the complexity of this program and find count of elements greater than current/picked element in first loop (array[])and store the count in solved array(solved[]) and loop through the end of the array[]. I have approached the problem using a general array based approach which turned out to have greater time complexity when 2nd loop is huge.
But If someone can suggest a better collection here in java that can reduce the complexity of this code that would also be highly appreciated.
for (int i = 0; i < input; i++) {
if (i < input - 1) {
count=0;
for (int j = i+1; j < input; j++) {
System.out.print((array[i])+" ");
System.out.print("> ");
System.out.print((array[j]) +""+(array[i] > array[j])+" ");
if (array[i] > array[j]) {
count++;
}
}
solved[i] = count;
}
}
for (int i = 0; i < input; i++) {
System.out.print(solved[i] + " ");
}
What I want to achieve in simpler terms
Input
Say I have 4 elements in my
array[] -->86,77,15,93
output
solved[]-->2 1 0 0
2 because after 86 there are only two elements 77,15 lesser than 86
1 because after 77 there is only 15 lesser than 77
rest 15 <93 hence 0,0
So making the code simpler and making the code faster aren't necessarily the same thing. If you want the code to be simple and readable, you could try a sort. That is, you could try something like
int[] solved = new int[array.length];
for (int i = 0; i < array.length; i++){
int[] afterward = Arrays.copyOfRange(array, i, array.length);
Arrays.sort(afterward);
solved[i] = Arrays.binarySearch(afterward, array[i]);
}
What this does it it takes a copy of the all the elements after the current index (and also including it), and then sorts that copy. Any element less than the desired element will be beforehand, and any element greater will be afterward. By finding the index of the element, you're finding the number of indices before it.
A disclaimer: There's no guarantee that this will work if duplicates are present. You have to manually check to see if there are any duplicate values, or otherwise somehow be sure you won't have any.
Edit: This algorithm runs in O(n2 log n) time, where n is the size of the original list. The sort takes O(n log n), and you do it n times. The binary search is much faster than the sort (O(log n)) so it gets absorbed into the O(n log n) from the sort. It's not perfectly optimized, but the code itself is very simple, which was the goal here.
With Java 8 streams you could reimplement it like this:
int[] array = new int[] { 86,77,15,93 };
int[] solved =
IntStream.range(0, array.length)
.mapToLong((i) -> Arrays.stream(array, i + 1, array.length)
.filter((x) -> x < array[i])
.count())
.mapToInt((l) -> (int) l)
.toArray();
There is actually a O(n*logn) solution, but you should use a self balancing binary search tree such as red-black tree.
Main idea of the algorithm:
You will iterate through your array from right to left and insert in the tree triples (value, sizeOfSubtree, countOfSmaller). Variable sizeOfSubtree will indicate the size of the subtree rooted at that element, while countOfSmaller counts the number of elements that are smaller than this element and appear at the right side of it in the original array.
Why binary search tree? An important property of BST is that all nodes in the left subtree are smaller than the current node, and all in the right subtree are greater.
Why self-balancing tree? Because this will guarantee you O(logn) time complexity while inserting a new element, so for n elements in array that will give O(n*logn) in total.
When you insert a new element you will also calculate the value of countOfSmaller by counting elements that are currently in the tree and are smaller than this element - exactly what are we looking for. Upon inserting in the tree compare the new element with the existing nodes, starting with the root. Important: if the value of the new element is greater than the value of the root, it means that is also greater than all the nodes in the left subtree of root. Therefore, set countOfSmaller to the sizeOfSubtree of root's left child + 1 (because the new element is also greater than root) and proceed recursively in the right subtree. If it is smaller than root, it goes to the left subtree of root. In both cases increment sizeOfSubtree of root and proceed recursively. While rebalancing the tree, just update the sizeOfSubtree for nodes that are included in left/right rotation and that's it.
Sample code:
public class Test
{
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count) {
value = val;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
System.out.println("For element " + val + " the number of smaller elements to the right is " + count);
}
}
static Node insert(Node node, int value, int countOfSmaller)
{
if (node == null)
return new Node(value, countOfSmaller);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1);
else
node.left = insert(node.left, value, countOfSmaller);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
/** Here goes the rebalancing part. In case that you plan to use AVL, you will need an additional variable that will keep the height of the subtree.
In case of red-black tree, you will need an additional variable that will indicate whether the node is red or black */
return node;
}
static int size(Node n)
{
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args)
{
int[] array = {13, 8, 4, 7, 1, 11};
Node root = insert(null, array[array.length - 1], 0);
for(int i = array.length - 2; i >= 0; i--)
insert(root, array[i], 0); /** When you introduce rebalancing, this should be root = insert(root, array[i], 0); */
}
}
As Miljen Mikic pointed out, the correct approach is using RB/AVL tree. Here is the code that can read and N testcase do the job as quickly as possible. Accepting Miljen code as the best approach to the given problem statement.
class QuickReader {
static BufferedReader quickreader;
static StringTokenizer quicktoken;
/** call this method to initialize reader for InputStream */
static void init(InputStream input) {
quickreader = new BufferedReader(new InputStreamReader(input));
quicktoken = new StringTokenizer("");
}
static String next() throws IOException {
while (!quicktoken.hasMoreTokens()) {
quicktoken = new StringTokenizer(quickreader.readLine());
}
return quicktoken.nextToken();
}
static int nextInt() throws IOException {
return Integer.parseInt(next());
}
static long nextLong() throws IOException {
return Long.parseLong(next());
}
static double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
public class ExecuteClass{
static int countInstance = 0;
static int solved[];
static int size;
static class Node {
public int value, countOfSmaller, sizeOfSubtree;
public Node left, right;
public Node(int val, int count, int len, int... arraytoBeused) {
countInstance++;
value = val;
size = len;
countOfSmaller = count;
sizeOfSubtree = 1; /** You always add a new node as a leaf */
solved = arraytoBeused;
solved[size - countInstance] = count;
}
}
static Node insert(Node node, int value, int countOfSmaller, int len, int solved[]) {
if (node == null)
return new Node(value, countOfSmaller, len, solved);
if (value > node.value)
node.right = insert(node.right, value, countOfSmaller + size(node.left) + 1, len, solved);
else
node.left = insert(node.left, value, countOfSmaller, len, solved);
node.sizeOfSubtree = size(node.left) + size(node.right) + 1;
return node;
}
static int size(Node n) {
return n == null ? 0 : n.sizeOfSubtree;
}
public static void main(String[] args) throws IOException {
QuickReader.init(System.in);
int testCase = QuickReader.nextInt();
for (int i = 1; i <= testCase; i++) {
int input = QuickReader.nextInt();
int array[] = new int[input];
int solved[] = new int[input];
for (int j = 0; j < input; j++) {
array[j] = QuickReader.nextInt();
}
Node root = insert(null, array[array.length - 1], 0, array.length, solved);
for (int ii = array.length - 2; ii >= 0; ii--)
insert(root, array[ii], 0, array.length, solved);
for (int jj = 0; jj < solved.length; jj++) {
System.out.print(solved[jj] + " ");
}
System.out.println();
countInstance = 0;
solved = null;
size = 0;
root = null;
}
}
}

Categories

Resources