How to get the top-k closest elements in a Java TreeSet? - java

Supposing I have this TreeSet<Integer>:
1 3 4 6 8 9 10
And I want the top-k "closest" elements to an input number x.
For example, with k=3 and x=5 I want to get:
4 6 3
Is there any way to do this?

It seems what you need to do is to get a headSet with all elements smaller than the target element and a tailSet for the bigger elements. Now the algorithm will be somewhat similar to merge phase of merge sort.
Take a descendingIterator of the headSet and an iterator over the tail set. Call these c_desc, and c_asc
Check which of the two elements is closer to the target value x. Take this value and advance the iterator
Take care for when one of the iterators is at the end of the corresponding set view
Continue doing that until you have taken k elements

By "closest to x" I assume you mean the lowest values of abs(n - x).
That is, for x=5, k=3:
1,3,4,6,8,9,10 -> 3,4,6
3,4,5,10,11,12 -> 3,4,5
0,1,2,5,6,7,8 -> 5,6,7
If that's the case, I would:
map each Integer to a Pair<Integer,Integer>
n -> new Pair(n, abs(n - x)) so one value is n, the other is its distance from x.
(write your own Pair, (ab)use Map.Entry, (ab)use Integer[2] or find one in a library)
sort the list of Pair<> using a comparator that uses the distance
take the first k elements from that sorted list.
Using Java 8 streams:
set.stream()
.map( n -> new Pair(n, Math.abs(x - n)))
.sorted(Comparator.comparing( p -> p.right())
.limit(k)
.map( p -> p.left())
.collect(Collectors.toSet());

Related

Lowest k pairwise absolute differences [duplicate]

This question already has answers here:
Find pairs with least difference
(3 answers)
Closed 6 months ago.
Given a list of Integers and a number k. We have to return the k minimum absolute differences between different pairs of Integers in sorted order (ascending)
eg: If the Given list of integers is 6, 9, 1, and k=2 Then the output should be [3,5]
Because the pairwise absolute differences are: |6-9|=3, |6-1|=5, |9-1|=8 the lowest 2 in ascending order will be 3,5
I solved this problem in following ways:
Calculate the pairwise absolute difference-> sort the list -> return the first k elements
Score: 7/15 Only 7 test cases passed out of 15. Rest I got Time Limit Exceeded Error
Instead of sorting I put all the elements in a min heap using the PriorityQueue in Java. The results were similar 8/15
Not sure what could be more efficient way to approach this problems. Any ideas?
Sort the list first
Init d = 1
Then get the absolute difference between elements 'd' distance apart and insert into a min-k heap. Quit as soon as your heap got k elements.
Go to step 3 with d = d + 1
Answer is in your heap. Complexity depends on k. If k ~ n^2, then it could be O(n^2) because you have to find all pairs. But it could be much better if k << n^2.

How to represent a 'long' number as nodes in a linked-list [JAVA]

I have a pragmatic task to solve:
Int and Long numbers that we can store in memory cells
are limited in size. One way to solve the problem would be to set up a linked-list in which each node in the list will contain one digit from the number so that the number itself will not be kept as a number but as a collection of its' digits- one after the other.
I have to create a Constructor, which gets a 'long' type of number and stores it in a format of a linked list.
By that I mean that if we take the number 233,674,318 , the Constructor would create a representation of this number as the following : 2 -> 3 -> 3 -> 6 -> 7 -> 4 -> 3 -> 1 -> 8
Could you please suggest me how can I approach this?
Thank you in advance!
You can extract a number's least significant digit (the one on the right) using the modulo operator. In this case, 233,674,318 % 10 will yield 8 (% signifies modulo). You can get rid of a number's least significant digit using division. 233,674,318 / 10 will yield 23,367,431 which is like removing the 8 from the number. Using these two operations you can extract all the digits from a number and build a list out of them.
Convert to String and take each char to create nodes
import java.util.*;
import java.util.stream.*
LinkedList<Integer> getList(long num){
String[] arr = String.valueOf(num).split("");
LinkedList<Integer> list = new LinkedList<>();
list.addAll(Stream.of(arr)
.mapToInt(x->Integer.parseInt(x))
.boxed()
.collect(Collectors.toList()));
return list;
}
This is a method you could use. Ultimately, it is a matter of either using the modulus to get every digit or using a split function on the String value of the long number to be then parsed and stored in a LinkedList of Integers.
If you are trying to save memory, as per your question, using integers for the linkedlist would be better as integers only use 32 bits whereas long uses 64 bits.

Determining best start and end points for line segment on polygon

I'm having trouble figuring out the best way to solve the following problem. I've tried out multiple methods of solving them but I'm always running into some corner cases.
The problem is the following:
You have a List of coordinates (x and y points) forming a closed polygon. This list is guaranteed to form a polygon with points ordered in a clockwise direction.
You are given a Set of coordinates (x and y points) which are from the above List of coordinates.
You must figure out the start and end points of the line formed using all points in the above Set.
The issue I'm having is that I can't figure out the method of finding the 'best' start and end points. For many scenarios, you can pick the first and last point (using the indices of the List) to form the start and end points, however this could result in a line which is longer than it has to be.
For example, let's say we have the following polygon:
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 0
And the following Set of coordinates our line segment must contain: 0, 7, 3.
If we find the min and max indices, we get index(0), index(7), so we can form the line 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7, which is a valid line but it is longer than it needs to be. The best line segment would be 7 -> 0 -> 1 -> 2 -> 3.
How can I find the best (shortest which contains all points in Set) line segment in an efficient manner?
For context: I'm working on an application which using JTS Geometries to draw shapes. The drawn shapes are smoothed using Bezier curves to result in 'curved edges'. After drawing the shapes (by dropping points), users can edit the shape. We want to figure out the start and end points using the points they modify (forms the Set above) so we can 'smooth' only the affected area.
Transform your set into sorted list, concatenate this list with it's copy, where every element is added with number of polygon vertices N, then find the longest empty run (neighbor difference) in this doubled list. Then get sublist of needed length, transform it to continuous range (but take elements modulo N)
(0,3,7) + (0+8,3+8,7+8) = (0,3,7,8,11,15)
max difference is 7-3, so the best case sublist starts with 7, it is
(7%8 .. 11%8) = (7,0,1,2,3)
so we have a Set and we nead to walk this set in the order of the index into List.
convert ISet = [Index(i, List) for i in Set]
next sort ISet
for pairs of consecutive items in ISet and the pair (last, first) compute the distances for that pair.
fined the pair with the max distances. Then the best end and start are that pair.

Java Ordering a map or list

if you have a map or list with a bunch of doubles between -1 and 1 you can order them from -1 to 1.
how ever it is perfect e.g ( 0.4 is after 0.3 but before 0.5 )
is it possible to simulate putting the numbers generally in the correct place but not perfect?
its hard to explain what I mean but I have drawn a diagram to help.
The x's are points on the number line
I don't want it to be perfectly sorted, neither randomly sorted but in-between; roughly sorted.
is this possible if so how?
You can use a TreeMap (constructor with Comparator-arg) or Collections.sort(List, Comparator) with a Comparator based on Double.compare(double, double).
This is correct for perfect sorting. About "roughly sorted", you have to write your own Comparator-logic. And please define your term how you really want to sort.
You haven't defined 'roughly sorted', but one option is "binning". Split the interval into n bins of width intervalsize/n. Store the bins in an array or list, and each bin is a list of values. Iterate once over the input set and distribute the values to their appropriate bins, which is O(n). You can improve the sorting by increasing the number of bins.
You can sort them first, and then run a set random swap of direct neighbours. For example, with a list size of n, you swap n times at random positions.

Create 2 arrays - 1st has random integers, 2nd has unique random integers

I am working on a school homework problem. I need to create 2 int[] arrays. The first array int[10] is filled with random integers. The second array has the same numbers as in the first array, but without any duplicates.
For example, assume my first array is 1,2,2,3,1,5,5,7,9,9. My second array would then be 1,2,3,5,7,9.
Could someone please point me in the right direction to solving this problem.
Put the numbers into a Set. Then retrieve numbers from the Set. Simple! Duplicates will automatically be removed!
I would do the following (assuming that it is homework and you shouldn't be doing anything too complicated)...
Sort the array using java.util.Arrays.sort(myArray); - this will order the numbers, and make sure that all repeating numbers are next to each other.
Loop through the array and keep a count of the number of unique numbers (ie compare the current number to the next number - if they're different, increment the counter by 1)
Create your second int[] array to the correct size (from point 2)
Repeat the same process as point 2, but fill your new array with the unique numbers, rather than incrementing a counter.
This should be enough to get you moving in the right direction. When you have some code, if you still have questions, come back to us and ask.
I recommend using a Set , but here's a way to do it without using a Set. (Note: This will work, but don't ask me about the efficiency of this!)
Have a function like this -
public static boolean isNumberInArray(int[] array, int number)
{
for(int i=0; i<array.length; i++)
{
if(number == array[i])
return true;
}
return false;
}
Now use this function before you make an insert into the new array. I leave you to figure out that part. It's homework after all!
Hints(WATTO explains it better):
a = sorted first array
lastItem = a[0]
append lastItem into new array
for i in 1 to length(a):
if a[i] != lastItem:
append a[i] into new array
lastItem = a[i]
#WATTO Studios has a good approach. Sorting is always useful when duplicates are involved.
I will suggest an alternative method using hash tables:
Create a hashing structure with an integer as key (the number in the original array) and a counter as a value.
Go through the original array and for each number encountered increment it's corresponding counter value in the hash table.
Go through the original array again. For each number check back the hash table. If the counter associated is greater than 1, remove the value and decrement the counter.
Let's see a practical case:
4 5 6 4 1 1 3
First pass will create the following table:
1 -> 2
3 -> 1
4 -> 2
5 -> 1
6 -> 1
Second pass step by step:
4 5 6 4 1 1 3
^
4 has a counter of 2 -> remove and decrement:
1 -> 2
3 -> 1
4 -> 1
5 -> 1
6 -> 1
5 6 4 1 1 3
^
5 has a counter of 1 -> ignore
6 has a counter of 1 -> ignore
4 has a counter of 1 -> ignore
1 has a counter of 2 -> remove and decrement
1 -> 1
3 -> 1
4 -> 1
5 -> 1
6 -> 1
5 6 4 1 3
^
1 has a counter of 1 -> ignore
3 has a counter of 1 -> ignore
Final array:
5 6 4 1 3
There are, of course, more efficient ways to handle the removal (since using an array implies shifting), like inserting the items into a linked list for example. I'll let you decide that. :)
Edit: An even faster approach, requiring a single pass:
Use the same hashing structure as above.
Go through the original array. For each item check the table. If the associated counter is 0, increment it to 1. If it's already 1, remove the item.

Categories