The following algorithm is used to find a basin in matrix. The whole question is as follows:
2-D matrix is given where each cell represents height of cell. Water
can flow from cell with higher height to lower one. A basin is when
there is no cell with lower height in the neighbours
(left,right,up,down,diagonal). You have to find maximum size basin
block.
I have implemented the code. I am looking for timeComplexity. In my opinion time complexity is O(n * m) where n and m is the row and column of the matrix. Please verify.
public final class Basin {
private Basin() {}
private static enum Direction {
NW(-1, -1), N(0, -1), NE(-1, 1), E(0, 1), SE(1, 1), S(1, 0), SW(1, -1), W(-1, 0);
private int rowDelta;
private int colDelta;
Direction(int rowDelta, int colDelta) {
this.rowDelta = rowDelta;
this.colDelta = colDelta;
}
public int getRowDelta() {
return rowDelta;
}
public int getColDelta() {
return colDelta;
}
}
private static class BasinCount {
private int count;
private boolean isBasin;
private int item;
BasinCount(int count, boolean basin, int item) {
this.count = count;
this.isBasin = basin;
this.item = item;
}
};
/**
* Returns the minimum basin.
* If more than a single minimum basin exists then returns any arbitrary basin.
*
* #param m : the input matrix
* #return : returns the basin item and its size.
*/
public static BasinData getMaxBasin(int[][] m) {
if (m.length == 0) { throw new IllegalArgumentException("The matrix should contain atleast one element."); }
final boolean[][] visited = new boolean[m.length][m[0].length];
final List<BasinCount> basinCountList = new ArrayList<>();
for (int i = 0; i < m.length; i++) {
for (int j = 0; j < m[0].length; j++) {
if (!visited[i][j]) {
basinCountList.add(scan(m, visited, i, j, m[i][j], new BasinCount(0, true, m[i][j])));
}
}
}
return getMaxBasin(basinCountList);
}
private static BasinData getMaxBasin(List<BasinCount> basinCountList) {
int maxCount = Integer.MIN_VALUE;
int item = 0;
for (BasinCount c : basinCountList) {
if (c.isBasin) {
if (c.count > maxCount) {
maxCount = c.count;
item = c.item;
}
}
}
return new BasinData(item, maxCount);
}
private static BasinCount scan(int[][] m, boolean[][] visited, int row, int col, int item, BasinCount baseCount) {
// array out of index
if (row < 0 || row == m.length || col < 0 || col == m[0].length) return baseCount;
// neighbor "m[row][col]" is lesser than me. now i cannot be the basin.
if (m[row][col] < item) {
baseCount.isBasin = false;
return baseCount;
}
// my neighbor "m[row][col]" is greater than me, thus not to add it to the basin.
if (m[row][col] > item) return baseCount;
// my neighbor is equal to me, but i happen to have visited him already. thus simply return without adding count.
// this is optimisitic recursion as described by rolf.
if (visited[row][col]) {
return baseCount;
}
visited[row][col] = true;
baseCount.count++;
for (Direction dir : Direction.values()) {
scan(m, visited, row + dir.getRowDelta(), col + dir.getColDelta(), item, baseCount);
/**
* once we know that current 'item' is not the basin, we do "want" to explore other dimensions.
* With the commented out code - consider: m3
* If the first 1 to be picked up is "1 # row2, col4." This hits zero, marks basin false and returns.
* Next time it starts with "1 # row 0, col 0". This never encounters zero, because "1 # row2, col4." is visited.
* this gives a false answer.
*/
// if (!baseCount.basin) {
// System.out.println(baseCount.item + "-:-:-");
// return baseCount;
// }
}
return baseCount;
}
Yes, your code (assuming it works; I have not tested it) is O(n * m) in time, and O(n * m) in space.
Complexities cannot be lower than O(n * m), since any cell can be a part of a neighbouring max-basin in the general case, and all must therefore be (in general) examined. Your complexity is O(n * m) due to the two nested for-loops in getMaxBasin, and the fact that visited[i][j] can only be set at a single place (inside scan()), and prohibits later visits of the same cell.
Due to recursion, every time you chain a call scan(), you are adding to the stack. With a sufficiently-long chain of scan() calls, you could run into stack limits. The worst-case scenario is a zig-zag pattern so that the stack ends up containing a scan() call for each an every cell.
Related
I want to choose a random item from a set, but the chance of choosing any item should be proportional to the associated weight
Example inputs:
item weight
---- ------
sword of misery 10
shield of happy 5
potion of dying 6
triple-edged sword 1
So, if I have 4 possible items, the chance of getting any one item without weights would be 1 in 4.
In this case, a user should be 10 times more likely to get the sword of misery than the triple-edged sword.
How do I make a weighted random selection in Java?
I would use a NavigableMap
public class RandomCollection<E> {
private final NavigableMap<Double, E> map = new TreeMap<Double, E>();
private final Random random;
private double total = 0;
public RandomCollection() {
this(new Random());
}
public RandomCollection(Random random) {
this.random = random;
}
public RandomCollection<E> add(double weight, E result) {
if (weight <= 0) return this;
total += weight;
map.put(total, result);
return this;
}
public E next() {
double value = random.nextDouble() * total;
return map.higherEntry(value).getValue();
}
}
Say I have a list of animals dog, cat, horse with probabilities as 40%, 35%, 25% respectively
RandomCollection<String> rc = new RandomCollection<>()
.add(40, "dog").add(35, "cat").add(25, "horse");
for (int i = 0; i < 10; i++) {
System.out.println(rc.next());
}
There is now a class for this in Apache Commons: EnumeratedDistribution
Item selectedItem = new EnumeratedDistribution<>(itemWeights).sample();
where itemWeights is a List<Pair<Item, Double>>, like (assuming Item interface in Arne's answer):
final List<Pair<Item, Double>> itemWeights = Collections.newArrayList();
for (Item i: itemSet) {
itemWeights.add(new Pair(i, i.getWeight()));
}
or in Java 8:
itemSet.stream().map(i -> new Pair(i, i.getWeight())).collect(toList());
Note: Pair here needs to be org.apache.commons.math3.util.Pair, not org.apache.commons.lang3.tuple.Pair.
You will not find a framework for this kind of problem, as the requested functionality is nothing more then a simple function. Do something like this:
interface Item {
double getWeight();
}
class RandomItemChooser {
public Item chooseOnWeight(List<Item> items) {
double completeWeight = 0.0;
for (Item item : items)
completeWeight += item.getWeight();
double r = Math.random() * completeWeight;
double countWeight = 0.0;
for (Item item : items) {
countWeight += item.getWeight();
if (countWeight >= r)
return item;
}
throw new RuntimeException("Should never be shown.");
}
}
139
There is a straightforward algorithm for picking an item at random, where items have individual weights:
calculate the sum of all the weights
pick a random number that is 0 or greater and is less than the sum of the weights
go through the items one at a time, subtracting their weight from your random number until you get the item where the random number is less than that item's weight
Use an alias method
If you're gonna roll a lot of times (as in a game), you should use an alias method.
The code below is rather long implementation of such an alias method, indeed. But this is because of the initialization part. The retrieval of elements is very fast (see the next and the applyAsInt methods they don't loop).
Usage
Set<Item> items = ... ;
ToDoubleFunction<Item> weighter = ... ;
Random random = new Random();
RandomSelector<T> selector = RandomSelector.weighted(items, weighter);
Item drop = selector.next(random);
Implementation
This implementation:
uses Java 8;
is designed to be as fast as possible (well, at least, I tried to do so using micro-benchmarking);
is totally thread-safe (keep one Random in each thread for maximum performance, use ThreadLocalRandom?);
fetches elements in O(1), unlike what you mostly find on the internet or on StackOverflow, where naive implementations run in O(n) or O(log(n));
keeps the items independant from their weight, so an item can be assigned various weights in different contexts.
Anyways, here's the code. (Note that I maintain an up to date version of this class.)
import static java.util.Objects.requireNonNull;
import java.util.*;
import java.util.function.*;
public final class RandomSelector<T> {
public static <T> RandomSelector<T> weighted(Set<T> elements, ToDoubleFunction<? super T> weighter)
throws IllegalArgumentException {
requireNonNull(elements, "elements must not be null");
requireNonNull(weighter, "weighter must not be null");
if (elements.isEmpty()) { throw new IllegalArgumentException("elements must not be empty"); }
// Array is faster than anything. Use that.
int size = elements.size();
T[] elementArray = elements.toArray((T[]) new Object[size]);
double totalWeight = 0d;
double[] discreteProbabilities = new double[size];
// Retrieve the probabilities
for (int i = 0; i < size; i++) {
double weight = weighter.applyAsDouble(elementArray[i]);
if (weight < 0.0d) { throw new IllegalArgumentException("weighter may not return a negative number"); }
discreteProbabilities[i] = weight;
totalWeight += weight;
}
if (totalWeight == 0.0d) { throw new IllegalArgumentException("the total weight of elements must be greater than 0"); }
// Normalize the probabilities
for (int i = 0; i < size; i++) {
discreteProbabilities[i] /= totalWeight;
}
return new RandomSelector<>(elementArray, new RandomWeightedSelection(discreteProbabilities));
}
private final T[] elements;
private final ToIntFunction<Random> selection;
private RandomSelector(T[] elements, ToIntFunction<Random> selection) {
this.elements = elements;
this.selection = selection;
}
public T next(Random random) {
return elements[selection.applyAsInt(random)];
}
private static class RandomWeightedSelection implements ToIntFunction<Random> {
// Alias method implementation O(1)
// using Vose's algorithm to initialize O(n)
private final double[] probabilities;
private final int[] alias;
RandomWeightedSelection(double[] probabilities) {
int size = probabilities.length;
double average = 1.0d / size;
int[] small = new int[size];
int smallSize = 0;
int[] large = new int[size];
int largeSize = 0;
// Describe a column as either small (below average) or large (above average).
for (int i = 0; i < size; i++) {
if (probabilities[i] < average) {
small[smallSize++] = i;
} else {
large[largeSize++] = i;
}
}
// For each column, saturate a small probability to average with a large probability.
while (largeSize != 0 && smallSize != 0) {
int less = small[--smallSize];
int more = large[--largeSize];
probabilities[less] = probabilities[less] * size;
alias[less] = more;
probabilities[more] += probabilities[less] - average;
if (probabilities[more] < average) {
small[smallSize++] = more;
} else {
large[largeSize++] = more;
}
}
// Flush unused columns.
while (smallSize != 0) {
probabilities[small[--smallSize]] = 1.0d;
}
while (largeSize != 0) {
probabilities[large[--largeSize]] = 1.0d;
}
}
#Override public int applyAsInt(Random random) {
// Call random once to decide which column will be used.
int column = random.nextInt(probabilities.length);
// Call random a second time to decide which will be used: the column or the alias.
if (random.nextDouble() < probabilities[column]) {
return column;
} else {
return alias[column];
}
}
}
}
public class RandomCollection<E> {
private final NavigableMap<Double, E> map = new TreeMap<Double, E>();
private double total = 0;
public void add(double weight, E result) {
if (weight <= 0 || map.containsValue(result))
return;
total += weight;
map.put(total, result);
}
public E next() {
double value = ThreadLocalRandom.current().nextDouble() * total;
return map.ceilingEntry(value).getValue();
}
}
A simple (even naive?), but (as I believe) straightforward method:
/**
* Draws an integer between a given range (excluding the upper limit).
* <p>
* Simulates Python's randint method.
*
* #param min: the smallest value to be drawed.
* #param max: the biggest value to be drawed.
* #return The value drawn.
*/
public static int randomInt(int min, int max)
{return (int) (min + Math.random()*max);}
/**
* Tests wether a given matrix has all its inner vectors
* has the same passed and expected lenght.
* #param matrix: the matrix from which the vectors length will be measured.
* #param expectedLenght: the length each vector should have.
* #return false if at least one vector has a different length.
*/
public static boolean haveAllVectorsEqualLength(int[][] matrix, int expectedLenght){
for(int[] vector: matrix){if (vector.length != expectedLenght) {return false;}}
return true;
}
/**
* Draws an integer between a given range
* by weighted values.
*
* #param ticketBlock: matrix with limits and weights for the drawing. All its
* vectors should have lenght two. The weights, instead of percentages, should be
* measured as integers, according to how rare each one should be draw, the rarest
* receiving the smallest value.
* #return The value drawn.
*/
public static int weightedRandomInt(int[][] ticketBlock) throws RuntimeException {
boolean theVectorsHaventAllLengthTwo = !(haveAllVectorsEqualLength(ticketBlock, 2));
if (theVectorsHaventAllLengthTwo)
{throw new RuntimeException("The given matrix has, at least, one vector with length lower or higher than two.");}
// Need to test for duplicates or null values in ticketBlock!
// Raffle urn building:
int raffleUrnSize = 0, urnIndex = 0, blockIndex = 0, repetitionCount = 0;
for(int[] ticket: ticketBlock){raffleUrnSize += ticket[1];}
int[] raffleUrn = new int[raffleUrnSize];
// Raffle urn filling:
while (urnIndex < raffleUrn.length){
do {
raffleUrn[urnIndex] = ticketBlock[blockIndex][0];
urnIndex++; repetitionCount++;
} while (repetitionCount < ticketBlock[blockIndex][1]);
repetitionCount = 0; blockIndex++;
}
return raffleUrn[randomInt(0, raffleUrn.length)];
}
I am trying to create a min heap but I am running into the issue where the numbers that are being displayed in my min heap are all in random order and there are extra 0's where there should be different values. This is the code for my class that does most of the work:
public class Heap211 {
static Random rand = new Random();
static public int[] Heap;
static public int size;
Heap211(){
Heap = new int[30];
size = 0;
}
static public int parent(int index){//location of parent
return index / 2;//array[k / 2]
}
static public int leftChild(int index){//location of left child
return index * 2;//array[k * 2]
}
static public int rightChild(int index){//location of right child
return index * 2 + 1;//array[k * 2 + 1]
}
static public boolean hasParent(int index){
return index > 1;
}
static public boolean hasLeftChild(int index){
return leftChild(index) * 2 <= size;
}
static public boolean hasRightChild(int index){
return rightChild(index * 2) + 1 <= size;
}
static public void swap(int[] a, int index1, int index2){//swaps nodes
int temp = a[index1];
a[index1] = a[index2];
a[index2] = temp;
}
static public int peek(){//peeks at the top of the stack (min value)
return Heap[1];
}
public static boolean isEmpty(){
return size == 0;
}
static int randInt(int min, int max){//generates random int between two numbers
return ((int) (Math.random()*(max - min))) + min;
}
public String toString(){
String result = "[";
if(!isEmpty()){
result += Heap[1];
for(int i = 2; i <= size; i++){
result += ", " + Heap[i];
}
}
return result + "]";
}
public void add(int value){//adds the give value to this priority queue in order
if(size + 1 >= Heap.length){
Heap = Arrays.copyOf(Heap, Heap.length * 2);
}
size++;
Heap[size + 1] = value;//add as rightmost leaf
//"bubble up" as necessary to fix ordering
int index = size + 1;
boolean found = false;
while(!found && hasParent(index) && hasLeftChild(index)){
int parent = parent(index);
if(Heap[index] < Heap[parent]){
swap(Heap, index, parent(index));
index = parent(index);
}else{//after done bubbling up
found = true;
}
}
}
public int remove(){
//move rightmost leaf to become new root
int result = peek();//last leaf -> root
Heap[1] = Heap[size];
size--;
//"bubble down" as necessary to fix ordering
int index = 1;
boolean found = false;
while(!found && hasLeftChild(index)){
int left = leftChild(index);
int right = rightChild(index);
int child = left;
if(hasRightChild(index) && Heap[right] < Heap[left]){
child = right;
}
if(Heap[index] > Heap[child]){
swap(Heap, index, child);
index = child;
}else{
found = true;//found proper location, stop the loop
}
}
return result;
}
This is the code for my main class:
public static void main(String[] args){
Heap211 pq = new Heap211();
for(int node = 1;node <= 30; node++){//loop runs 30 times for 30 nodes
int smValue = randInt(0,2);//generates random number between 1 and 0
if(smValue == 0){//if random number is 0 then it will add random number to heap
int value = randInt(0,100);//generates random number between 0 and 100
System.out.println(node + " Add " + value + ": ");
pq.add(value);//adds random number
System.out.println(pq);//print heap
}else if(smValue == 1 && pq.isEmpty()){
int value = pq.remove();
System.out.println(node + " Remove " + value + ": ");
System.out.println(pq);
}
}
I have a GUI that displays all the numbers but I am getting the wrong output. Any helpful pointers would be greatly appreciated! Thanks.
I found a few problems in your code.
Your hasLeftChild function is wrong. You have return leftChild(index*2) <= size;. But you really should be checking for leftChild(index) <= size. You have a similar error in your hasRightChild function.
Not sure why you pass an array parameter to swap. The only array in which you swap stuff is the Heap array, which is a member of the class.
You have an error in your add method. You increment the size, and then add an item. That is:
size++;
Heap[size + 1] = value;
So imagine what happens when you add the first item. size is equal to 0, and you increment it to 1. Then you add the value at index size+1. So your array contains [0, 0, value]. That's probably the source of your extra 0's. I think what you want is:
Heap[size] = value;
size++;
You'll have to modify the rest of your code to take that into account.
Your "bubble up" loop is kind of wonky. You have:
while (!found && hasParent(index) && hasLeftChild(index))
That's never going to bubble anything up, because when you add something to the last element of the heap, that node doesn't have a left child. You also don't need the found flag. You can write:
while (hasParent(index) && Heap[index] < Heap[parent]]) {
swap(Heap, index, parent(index));
index = parent(index);
}
I can't guarantee that those are the only errors in your code, but they're the ones I found in a quick review of your code.
On a general note, why in the world are you creating a 1-based binary heap in a language that has 0-based arrays? There's no need to do that, and it's confusing as heck. For why I think it's a bad idea, see https://stackoverflow.com/a/49806133/56778 and http://blog.mischel.com/2016/09/19/but-thats-the-way-weve-always-done-it/.
Finally, you should learn to use your debugger, as suggested in comments. Take the time to do it now. It will save you hours of frustration.
I need to compress a list of intervals into a smaller list. Let me explain:
For example I have a list containing intervals [1,4],[2,5],[5,7],[10,11],[13,20],[19,21] and i want to join the intersecting intervals and return a list [1,7],[10,11],[13,21] that transforming intersecting intervals into a single longer interval.
For this I wrote this method:
public List compress(List<Interval> intervals) {
for (int j = 0; j < intervals.size(); j++) {
Interval a = intervals.get(j);
int aIndex = j;
for (int i = 1 + aIndex; i < intervals.size(); i++) {
Interval b = intervals.get(i);
if (a.intersects(b)) {
//the union method return a union of two intervals. For example returns [1,7] for [1,4] and [2,5]
intervals.add(j, a.union(b));
intervals.remove(j+1);
intervals.remove(i);
}
}
}
return intervals;
}
This seems to work fine for the first pair of intervals that are checked but it stops there. That is the final output is a list containing [1, 5],[5, 7],[10, 11],[13, 20],[19, 21].
I have found that this may be a problem with illegal removing of elements from a list? https://codereview.stackexchange.com/questions/64011/removing-elements-on-a-list-while-iterating-through-it?newreg=cc3f30e670e24cc2b05cd1fa2492906f
But I have no idea how to get around this.
Please can anyone give me a hint.
Notice: Sorry if I did anything wrong as this is my first post to stackoverflow. And thanks to anyone that will try to help.
UPDATE:
Here is the solution I found after Maraboc proposed to create a copy of the list and manipulate that one.
That seems to work.
public List compress(List<Interval> intervals) {
List<Interval> man = intervals;
for (int j = 0; j < intervals.size(); j++) {
Interval a = intervals.get(j);
int aIndex = j;
for (int i = 1 + aIndex; i < intervals.size(); i++) {
Interval b = intervals.get(i);
if (a.intersects(b)) {
a = a.union(b);
man.add(j,a);
man.remove(j+1);
man.remove(i);
i--;
}
}
}
return intervals;
}
Thank you everyone.
You are actually NOT using iterator, you are using for-cycles and select elements from list based on their position, therefore you do not have to be afraid of "I am not able to remove while iterating" issue.
I posted this question first to stackexchange by mistake. They redirected me to this place and the question was put on hold. But before that happened Maraboc[a link](https://codereview.stackexchange.com/users/87685/maraboc
)
Helped with an idea. He told me to create a new list and modify that one. I did that and it seems to work. The updated solution will be in the updated question.
Just for the fun of it I took an existing Interval Tree and added a minimise method that seems to work nicely.
/**
* Title: IntervlTree
*
* Description: Implements a static Interval Tree. i.e. adding and removal are not possible.
*
* This implementation uses longs to bound the intervals but could just as easily use doubles or any other linear value.
*
* #author OldCurmudgeon
* #version 1.0
* #param <T> - The Intervals to work with.
*/
public class IntervalTree<T extends IntervalTree.Interval> {
// My intervals.
private final List<T> intervals;
// My center value. All my intervals contain this center.
private final long center;
// My interval range.
private final long lBound;
private final long uBound;
// My left tree. All intervals that end below my center.
private final IntervalTree<T> left;
// My right tree. All intervals that start above my center.
private final IntervalTree<T> right;
public IntervalTree(List<T> intervals) {
if (intervals == null) {
throw new NullPointerException();
}
// Initially, my root contains all intervals.
this.intervals = intervals;
// Find my center.
center = findCenter();
/*
* Builds lefts out of all intervals that end below my center.
* Builds rights out of all intervals that start above my center.
* What remains contains all the intervals that contain my center.
*/
// Lefts contains all intervals that end below my center point.
final List<T> lefts = new ArrayList<>();
// Rights contains all intervals that start above my center point.
final List<T> rights = new ArrayList<>();
long uB = Long.MIN_VALUE;
long lB = Long.MAX_VALUE;
for (T i : intervals) {
long start = i.getStart();
long end = i.getEnd();
if (end < center) {
lefts.add(i);
} else if (start > center) {
rights.add(i);
} else {
// One of mine.
lB = Math.min(lB, start);
uB = Math.max(uB, end);
}
}
// Remove all those not mine.
intervals.removeAll(lefts);
intervals.removeAll(rights);
uBound = uB;
lBound = lB;
// Build the subtrees.
left = lefts.size() > 0 ? new IntervalTree<>(lefts) : null;
right = rights.size() > 0 ? new IntervalTree<>(rights) : null;
// Build my ascending and descending arrays.
/**
* #todo Build my ascending and descending arrays.
*/
}
/*
* Returns a list of all intervals containing the point.
*/
List<T> query(long point) {
// Check my range.
if (point >= lBound) {
if (point <= uBound) {
// Gather all intersecting ones.
List<T> found = intervals
.stream()
.filter((i) -> (i.getStart() <= point && point <= i.getEnd()))
.collect(Collectors.toList());
// Gather others.
if (point < center && left != null) {
found.addAll(left.query(point));
}
if (point > center && right != null) {
found.addAll(right.query(point));
}
return found;
} else {
// To right.
return right != null ? right.query(point) : Collections.<T>emptyList();
}
} else {
// To left.
return left != null ? left.query(point) : Collections.<T>emptyList();
}
}
/**
* Blends the two lists together.
*
* If the ends touch then make them one.
*
* #param a
* #param b
* #return
*/
static List<Interval> blend(List<Interval> a, List<Interval> b) {
// Either empty - lreturn the other.
if (a.isEmpty()) {
return b;
}
if (b.isEmpty()) {
return a;
}
Interval aEnd = a.get(a.size() - 1);
Interval bStart = b.get(0);
ArrayList<Interval> blended = new ArrayList<>();
// Do they meet?
if (aEnd.getEnd() >= bStart.getStart() - 1) {
// Yes! merge them.
// Remove the last.
blended.addAll(a.subList(0, a.size() - 1));
// Add a combined one.
blended.add(new SimpleInterval(aEnd.getStart(), bStart.getEnd()));
// Add all but the first.
blended.addAll(b.subList(1, b.size()));
} else {
// Just join them.
blended.addAll(a);
blended.addAll(b);
}
return blended;
}
static List<Interval> blend(List<Interval> a, List<Interval> b, List<Interval>... more) {
List<Interval> blended = blend(a, b);
for (List<Interval> l : more) {
blended = blend(blended, l);
}
return blended;
}
List<Interval> minimise() {
// Calculate min of left and right.
List<Interval> minLeft = left != null ? left.minimise() : Collections.EMPTY_LIST;
List<Interval> minRight = right != null ? right.minimise() : Collections.EMPTY_LIST;
// My contribution.
long meLeft = minLeft.isEmpty() ? lBound : Math.max(lBound, minLeft.get(minLeft.size() - 1).getEnd());
long meRight = minRight.isEmpty() ? uBound : Math.min(uBound, minRight.get(0).getEnd());
return blend(minLeft,
Collections.singletonList(new SimpleInterval(meLeft, meRight)),
minRight);
}
private long findCenter() {
//return average();
return median();
}
protected long median() {
if (intervals.isEmpty()) {
return 0;
}
// Choose the median of all centers. Could choose just ends etc or anything.
long[] points = new long[intervals.size()];
int x = 0;
for (T i : intervals) {
// Take the mid point.
points[x++] = (i.getStart() + i.getEnd()) / 2;
}
Arrays.sort(points);
return points[points.length / 2];
}
/*
* What an interval looks like.
*/
public interface Interval {
public long getStart();
public long getEnd();
}
/*
* A simple implemementation of an interval.
*/
public static class SimpleInterval implements Interval {
private final long start;
private final long end;
public SimpleInterval(long start, long end) {
this.start = start;
this.end = end;
}
#Override
public long getStart() {
return start;
}
#Override
public long getEnd() {
return end;
}
#Override
public String toString() {
return "{" + start + "," + end + "}";
}
}
/**
* Test code.
*
* #param args
*/
public static void main(String[] args) {
/**
* #todo Needs MUCH more rigorous testing.
*/
// Test data.
long[][] data = {
{1, 4}, {2, 5}, {5, 7}, {10, 11}, {13, 20}, {19, 21},};
List<Interval> intervals = new ArrayList<>();
for (long[] pair : data) {
intervals.add(new SimpleInterval(pair[0], pair[1]));
}
// Build it.
IntervalTree<Interval> test = new IntervalTree<>(intervals);
// Check minimise.
List<Interval> min = test.minimise();
System.out.println("Minimise test: ---");
System.out.println(min);
}
}
For your algorithm to work, the intervals must be sorted, say by start.
Then the for-i loop can make a the longest possible interval.
if (a.intersects(b)) {
a = a.union(b);
intervals.remove(i);
--i; // So we remain at old i value.
}
} // for i
intervals.set(j, a);
The reason for these requirements is that intervals A, B, C might form one long interval ABC, whereas C. B, A might.
Indeed the problem is that when you remove an element from the list, then all subsequent elements will be shifted. At around j I'm guessing it doesn't change because you insert then remove an item at the same location. But the removal at position i will shift all elements in the list.
What you could be doing, instead of removing the elements, is to put a null value at that position, so that the indices remain the same. You will then have to perform a final pass to remove null elements from the array (and check for nulls before comparing).
You could also run your inner loop backwards (from max i down to j) so that any element that gets shifted after i has already been processed.
This question already has answers here:
Getting permutations of an int[] removing duplicates sets
(5 answers)
Closed 7 years ago.
I want to generate all distinct permutations of array of integers. The array may contain duplicates. but i want to generate all distinct permutations. I have tried next permutation and recursive methods which tend to be very slow. Please suggest.
There are n! different permutations of n elements. Generating a single permutation is cost n (strictly) so the minimum cost of any permutation generation algorithm would be O(n*n!)
Steinhaus–Johnson–Trotter algorithm is one of those algorithms. There are improvements like Shimon Even's and other algorithms like Heap's but none get them under O(n*n!)
Googling "permutation algorithm" gets several different algorithms you can implement, although most use recursion and that means another stack step. Steinhaus–Johnson–Trotter is defined as iterative, so shouldn't get that problem.
Here's a Java implementation
import java.util.Arrays;
import java.util.Iterator;
/**
* this implementation is based in Steinhaus–Johnson–Trotter algorithm and
* Shimon Even's improvement;
*
* #see https
* ://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm
*
*/
public class Permutations implements Iterator<int[]> {
/**
* direction[i] = -1 if the element i has to move to the left, +1 to the
* right, 0 if it does not need to move
*/
private int[] direction;
/**
* inversePermutation[i] is the position of element i in permutation; It's
* called inverse permutation because if p2 is the inverse permutation of
* p1, then p1 is the inverse permutation of p2
*/
private int[] inversePermutation;
/**
* current permutation
*/
private int[] permutation;
/**
* #param numElements
* >= 1
*/
public Permutations(int numElements) {
// initial permutation
permutation = new int[numElements];
for (int i = 0; i < numElements; i++) {
permutation[i] = i;
}
// the support elements
inversePermutation = Arrays.copyOf(permutation, numElements);
direction = new int[numElements];
Arrays.fill(direction, -1);
direction[0] = 0;
}
/**
* Swaps the elements in array at positions i1 and i2
*
* #param array
* #param i1
* #param i2
*/
private static void swap(int[] array, int i1, int i2) {
int temp = array[i1];
array[i1] = array[i2];
array[i2] = temp;
}
/**
* prepares permutation to be the next one to return
*/
private void buildNextPermutation() {
// find the largest element with a nonzero direction, and swaps it in
// the indicated direction
int index = -1;
for (int i = 0; i < direction.length; i++) {
if (direction[permutation[i]] != 0
&& (index < 0 || permutation[index] < permutation[i])) {
index = i;
}
}
if (index < 0) {
// there are no more permutations
permutation = null;
} else {
// element we're moving
int chosenElement = permutation[index];
// direction we're moving
int dir = direction[chosenElement];
// index2 is the new position of chosenElement
int index2 = index + dir;
// we'll swap positions elements permutation[index] and
// permutation[index2] in permutation, to keep inversePermutation we
// have to swap inversePermutation's elements at index
// permutation[index] and permutation[index2]
swap(inversePermutation, permutation[index], permutation[index2]);
swap(permutation, index, index2);
// update directions
if (index2 == 0 || index2 == permutation.length - 1
|| permutation[index2 + dir] > permutation[index2]) {
// direction of chosen element
direction[chosenElement] = 0;
}
// all elements greater that chosenElement set its direction to +1
// if they're before index-1 or -1 if they're after
for (int i = chosenElement + 1; i < direction.length; i++) {
if (inversePermutation[i] > index2) {
direction[i] = -1;
} else {
direction[i] = 1;
}
}
}
}
#Override
public boolean hasNext() {
return permutation != null;
}
#Override
public int[] next() {
int[] result = Arrays.copyOf(permutation, permutation.length);
buildNextPermutation();
return result;
}
}
I am using array based MinHeap in java. I am trying to create a custom method which can remove any element not only root from the heap but couldn't. Below is MinHeap code-
public class MinHeap {
/** Fixed-size array based heap representation */
private int[] h;
/** Number of nodes in the heap (h) */
private int n = 0;
/** Constructs a heap of specified size */
public MinHeap(final int size) {
h = new int[size];
}
/** Returns (without removing) the smallest (min) element from the heap. */
public int peek() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
return h[0];
}
/** Removes and returns the smallest (min) element from the heap. */
public int poll() {
if (isEmpty()) {
throw new RuntimeException("Heap is empty!");
}
final int min = h[0];
h[0] = h[n - 1];
if (--n > 0)
siftDown(0);
return min;
}
/** Checks if the heap is empty. */
public boolean isEmpty() {
return n == 0;
}
/** Adds a new element to the heap and sifts up/down accordingly. */
public void add(final int value) {
if (n == h.length) {
throw new RuntimeException("Heap is full!");
}
h[n] = value;
siftUp(n);
n++;
}
/**
* Sift up to make sure the heap property is not broken. This method is used
* when a new element is added to the heap and we need to make sure that it
* is at the right spot.
*/
private void siftUp(final int index) {
if (index > 0) {
final int parent = (index - 1) / 2;
if (h[parent] > h[index]) {
swap(parent, index);
siftUp(parent);
}
}
}
/**
* Sift down to make sure that the heap property is not broken This method
* is used when removing the min element, and we need to make sure that the
* replacing element is at the right spot.
*/
private void siftDown(int index) {
final int leftChild = 2 * index + 1;
final int rightChild = 2 * index + 2;
// Check if the children are outside the h bounds.
if (rightChild >= n && leftChild >= n)
return;
// Determine the smallest child out of the left and right children.
final int smallestChild = h[rightChild] > h[leftChild] ? leftChild
: rightChild;
if (h[index] > h[smallestChild]) {
swap(smallestChild, index);
siftDown(smallestChild);
}
}
/** Helper method for swapping h elements */
private void swap(int a, int b) {
int temp = h[a];
h[a] = h[b];
h[b] = temp;
}
/** Returns the size of heap. */
public int size() {
return n;
}
}
How can i design a method to remove any element from this MinHeap?
If you know the index of the element to be removed,
private void removeAt(int where) {
// This should never happen, you should ensure to call it only with valid indices
if (n == 0) throw new IllegalArgumentException("Trying to delete from empty heap");
if (where >= n) throw new IllegalArgumentException("Informative error message");
// Now for the working cases
if (where == n-1) {
// removing the final leaf, trivial
--n;
return;
}
// other nodes
// place last leaf into place where deletion occurs
h[where] = h[n-1];
// take note that we have now one element less
--n;
// the new node here can be smaller than the previous,
// so it might be smaller than the parent, therefore sift up
// if that is the case
if (where > 0 && h[where] > h[(where-1)/2]) {
siftUp(where);
} else if (where < n/2) {
// Now, if where has a child, the new value could be larger
// than that of the child, therefore sift down
siftDown(where);
}
}
The exposed function to remove a specified value (if present) would be
public void remove(int value) {
for(int i = 0; i < n; ++i) {
if (h[i] == value) {
removeAt(i);
// assumes that only one value should be removed,
// even if duplicates are in the heap, otherwise
// replace the break with --i to continue removing
break;
}
}
}
Summarising, we can remove a node at a given position by replacing the value with the value of the last leaf (in the cases where the removal is not trivial), and then sifting up or down from the deletion position. (Only one or none sift needs to be done, depending on a comparison with the parent and/or children, if present.)
That works because the heap invariant is satisfied for the parts of the tree above and below the deletion position, so if the new value placed there by the swap is smaller than the parent, sifting up will place it in its proper position above the deletion position. All elements moved are smaller than any element in the children, so the heap invariant is maintained for the part below (and including) the deletion position.
If the new value is larger than one of the direct children, it's basically a removal of the root from the sub-heap topped at the deletion position, so the siftDown restores the heap invariant.
The fix for the mentioned flaw in the siftDown method is to set smallestChild to leftChild if rightChild >= n:
final int smallestChild = (rightChild >= n || h[rightChild] > h[leftChild]) ? leftChild
: rightChild;