I have a list of lines and points and I need to get the list of connected lines based on points.
The input is Line and its 2 points so in the above example input is
In Tabular format
And the output should be 2 lists
[1,2,3,4,5,6,7] and [8]
I was creating a map of point to list of lines it belongs
A - 1
B - 1,2,3
C - 2
...
and then trying to merge the list of lines where common points are found. But not able to find the correct way to merge those lines.
Can there be simple or another solution to it?
Are 3 and 5 different lines?
If yes, then it is obvious that each line can have no more than 2 points.
If no, then a tabular format is not appropriate.
If I were you, I would do one Map with a line as the key and a List of points as the value.
Then create an interface to define if a point belongs to several lines at once.
One solution is to create an adjacent map of points to point-lines.
You define what are the adjacent points of a given point and what are the lines:
class PointAdj {
String point;
String line;//Or int
}
Define the map as:
Map<String, List<PointAdj>> pontAdjMap = new HashMap<>();
Start reading from the table and fill the map:
(I assume the input is a two dimensional array called input)
for (int i =0; i < input.length; i++) {
String[] row = input[i];
List<PointAdj>> adj = pontAdjMap.putIfAbsent(row[1], new ArrayList<>());
if(adj == null) {
adj = pontAdjMap.get(row[1]);
}
adj.add(new PointAdj(row[2], row[0]));
//Also put the reverse side
}
Now pontAdjMap contains all points with their adjacent points.
Now define a list of Set to add lines and loop the map and add lines as much as possible.
Use a queue to continuously traverse adjacent points;
List<Set<String>> lines = new ArrayList<>();
final Set<String> calculated = new HashSet();//Takes care of redundant processing of points;
pontAdjMap.keySet().foreach(pointInMap->{
Set<String> lineSet = new HashSet();
Queue<String> queue = new LinkedList<String>();
queue.offer(pointInMap);
while(!queue.isEmpty()) {
String point = queue.poll();
if(calculated.add(point)) {
for(PointAdj pa: pontAdjMap.get(point)) {
lineSet.add(pa.line);
queue.offer(pa.point);
}
}
}
if(lineSet.size() > 0) {
lines.add(lineSet);
}
});
Now lines should be the final result.
Please note that I did't test this solution and it may contain some edge case issues. But I think the overall idea is ok.
Related
https://leetcode.com/discuss/interview-question/373202/amazon-oa-2019-optimal-utilization Given 2 lists a and b. Each element is a pair of integers where the first integer represents the unique id and the second integer represents a value. Your task is to find an element from a and an element form b such that the sum of their values is less or equal to target and as close to target as possible. Return a list of ids of selected elements. If no pair is possible, return an empty list.
question was this but I had to use Lists (like <<1,1>, <2,2> <3,3>>)
my solution was something like below. I kept failing some test cases with a NullPointerException. I am trying to find out WHAT SPECIFIC INPUT(foreground, background) COULD HAVE CAUSED THIS. (the assessment website HID the error line). the problem did not have any specifications or guarantees like 0 < deviceCapacity < 1000000, so I do NOT know what was passed in
Things I checked for:
foreground and background were not null. they did not have null values (how i checked is below)
I put a System.out.println(foregroundApplications.get(i)); System.out.println(backgroundApplications.get(j)) just before initializing "sums", the goal being to see if any values were something like null or <null, null>, but they were all valid number pairs like <1,8>. (if it was null, it would have printed null right? unsure about this). example of what I saw (there were no nulls): <1, 14> <2, 14> <3, 14> <4, 14>
i checked in the beginning if the lists (foreground and background) were null with an if(foregroundApps == null), they weren't.
I can't change my code anymore, this was an assessment with obfuscated test cases which I am trying to figure out.
P.S. If there is a better approach than O(M*N) time, I would like to know
public List<List<Integer>> optimize(int deviceCapacity, List<List<Integer> foregroundApplications, List<List<Integer>> backgroundApplications)
{
TreeMap<Integer, List<List<Integer>>> map = new TreeMap<>();
for(int i = 0; i < foregroundApplications.size(); i++)
{
for(int j = 0; j < backgroundApplications.size(); j++)
{
int sum = foregroundApplications.get(i).get(1) + backgroundApplications.get(j).get(1);
if(sum<=deviceCapacity)
{
List<List<Integer>> list= new ArrayList<>();
if(map.containsKey(sum))
{
list = map.get(sum);
}
List<Integer> pair = new ArrayList<>();
pair.add(foregroundApplications.get(i).get(0));
pair.add(backgroundApplications.get(j).get(0));
list.add(pair);
map.put(sum, list);
}
}
}
if(map.size() == 0)
{
List<List<Integer>> list= new ArrayList<>();
List<Integer> emptyPair = new ArrayList<>();
emptyPair.add(null);
emptyPair.add(null);
list.add(emptyPair);
return list;
}
return map.get(map.lastKey());
}
Right now I have an array of "Dragon"s. Each item has two values. An ID and a Count. So my array would look something like this:
Dragon[] dragons = { new Dragon(2, 4),
new Dragon(83, 199),
new Dragon(492, 239),
new Dragon(2, 93),
new Dragon(24, 5)
};
As you can see, I have two Dragons with the ID of 2 in the array. What I would like to accomplish is, when a duplicate is found, just add the count of the duplicate to the count of the first one, and then remove the duplicate Dragon.
I've done this sort of successfully, but I would end up with a null in the middle of the array, and I don't know how to remove the null and then shuffle them.
This is what I have so far but it really doesn't work properly:
public static void dupeCheck(Dragon[] dragons) {
int end = dragons.length;
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (dragons[i] != null && dragons[j] != null) {
if (dragons[i].getId() == dragons[j].getId()) {
dragons[i] = new Item(dragons[i].getId(), dragons[i].getCount() + dragons[j].getCount());
dragons[j] = null;
end--;
j--;
}
}
}
}
}
You should most probably not maintain the dragon count for each dragon in the dragon class itself.
That aside, even if you are forced to use an array, you should create an intermeditate map to store your dragons.
Map<Integer, Dragon> idToDragon = new HashMap<>();
for (Dragon d : yourArray) {
// fetch existing dragon with that id or create one if none present
Dragon t = idToDragon.computeIfAbsent(d.getId(), i -> new Dragon(i, 0));
// add counts
t.setCount(t.getCount() + d.getCount());
// store in map
idToDragon.put(d.getId(), t);
}
Now the map contains a mapping between the dragons' ids and the dragons, with the correct counts.
To create an array out of this map, you can just
Dragon[] newArray = idToDragon.values().toArray(new Dragon[idToDragon.size()]);
You may be force to store the result in an array but that doesn't mean that you're force to always use an array
One solution could be using the Stream API, group the items adding the count and save the result into an array again. You can get an example of how to use the Stream API to sum values here. Converting a List<T> into a T[] is quite straightforward but anyways, you have an example here
The size of an array cannot be changed after it's created.
So you need to return either a new array or list containing the merged dragons.
public static Dragon[] merge(Dragon[] dragonArr) {
return Arrays.stream(dragonArr)
// 1. obtain a map of dragon IDs and their combined counts
.collect(groupingBy(Dragon::getId, summingInt(Dragon::getCount)))
// 2. transform the map entries to dragons
.entrySet().stream().map(entry -> new Dragon(entry.getKey(), entry.getValue()))
// 3. collect the result as an array
.toArray(Dragon[]::new);
}
I know this question has been answered on "how to find" many times, however I have a few additional questions. Here is the code I have
public static void main (String [] args){
List<String> l1= new ArrayList<String>();
l1.add("Apple");
l1.add("Orange");
l1.add("Apple");
l1.add("Milk");
//List<String> l2=new ArrayList<String>();
//HashSet is a good choice as it does not allow duplicates
HashSet<String> set = new HashSet<String>();
for( String e: l1){
//if(!(l2).add(e)) -- did not work
if(!(set).add(e)){
System.out.println(e);
}
Question 1:The list did not work because List allows Duplicate while HashSet does not- is that correct assumption?
Question 2: What does this line mean: if(!(set).add(e))
In the for loop we are checking if String e is in the list l1 and then what does this line validates if(!(set).add(e))
This code will print apple as output as it is the duplicate value.
Question 3: How can i have it print non Duplicate values, just Orange and Milk but not Apple? I tried this approach but it still prints Apple.
List unique= new ArrayList(new HashSet(l1));
Thanks in advance for your time.
1) Yes that is correct. We often use sets to remove duplicates.
2) The add method of HashSet returns false when the item is already in the set. That's why it is used to check whether the item exists in the set.
3) To do this, you need to count up the number of occurrances of each item in the array, store them in a hash map, then print out those items that has a count of 1. Or, you could just do this (which is a little dirty and is slower! However, this approach takes a little less space than using a hash map.)
List<String> l1= new ArrayList<>();
l1.add("Apple");
l1.add("Orange");
l1.add("Apple");
l1.add("Milk");
HashSet<String> set = new HashSet<>(l1);
for (String item : set) {
if (l1.stream().filter(x -> !x.equals(item)).count() == l1.size() - 1) {
System.out.println(item);
}
}
You're right.
Well... adding to the collection doesn't necessary need to return anything. Fortunately guys from the Sun or Oracle decided to return a message if the item was successfully added to the collection or not. This is indicated by true/false return value. true for a success.
You can extend your current code with the following logic: if element wasn't added successfully to the set, it means it was a duplicate so add it to another set Set<> duplicates and later remove all duplicates from the Set.
Question 1:The list did not work because List allows Duplicate while HashSet does not- is that correct assumption?
That is correct.
Question 2: What does this line mean: if(!(set).add(e)) In the for loop we are checking if String e is in the list l1 and then what does this line validates if(!(set).add(e))
This code will print apple as output as it is the duplicate value.
set.add(e) attempts to add an element to the set, and it returns a boolean indicating whether it was added. Negating the result will cause new elements to be ignored and duplicates to be printed. Note that if an element is present 3 times it will be printed twice, and so on.
Question 3: How can i have it print non Duplicate values, just Orange and Milk but not Apple? I tried this approach but it still prints Apple. List<String> unique= new ArrayList<String>(new HashSet<String>(l1));
There are a number of ways to approach it. This one doesn't have the best performance but it's pretty straightforward:
for (int i = 0; i < l1.size(); i++) {
boolean hasDup = false;
for (int j = 0; j < l1.size(); j++) {
if (i != j && l1.get(i).equals(l1.get(j))) {
hasDup = true;
break;
}
}
if (!hasDup) {
System.out.println(e);
}
}
With the /java8 power...
public static void main(String[] args) {
List<String> l1 = new ArrayList<>();
l1.add("Apple");
l1.add("Orange");
l1.add("Apple");
l1.add("Milk");
// remove duplicates
List<String> li = l1.parallelStream().distinct().collect(Collectors.toList());
System.out.println(li);
// map with duplicates frequency
Map<String, Long> countsList = l1.stream().collect(Collectors.groupingBy(fe -> fe, Collectors.counting()));
System.out.println(countsList);
// filter the map where only once
List<String> l2 = countsList.entrySet().stream().filter(map -> map.getValue().longValue() == 1)
.map(map -> map.getKey()).collect(Collectors.toList());
System.out.println(l2);
}
So I'm doing a Star Trek themed project where I need to take a list of crew members and the planets they've visited and generate a log report for Starfleet.
For example this...
Guinan,Drema IV
Picard,Gamalon V
Barclay,Valo III
Riker,Theydat IV
Pulaski,Alpha Moon
Troi,Tessen III
...
Needs to become this
Acamar III:
B. Crusher 11
Barclay 6
Data 15
Gomez 3
Guinan 4
Lefler 5
O'Brien 12
Ogawa 4
Picard 5
Pulaski 14
Riker 12
Troi 9
W. Crusher 4
Worf 14
Yar 3
...
To do this I need to use a generic structure that automatically sorts the incoming data so I decided to use a Tree Map of 15-element int arrays to store the number of visits each crew member has made to a given planet.
My question is, since I am very new to Java, how would I get a value from an array element inside the tree map and update the value inside a given array element? My problem is that all the examples I can find about working with Tree Map either don't involve arrays inside of them or don't show how to get a value and update values after the first insertion. Below I've given my current psuedocode with my best guess as to how to accomplish this. If anyone knows of a way to do this, or a better method entirely please suggest it.
P.S. I'm going to implement the loop I need after I can get a single iteration written correctly
EDIT: For clarity, each element of the 15-element int array corresponds to a crew member so for example Data would be array[2] and Yar would be array[14]
import java.util.*;
public class TreeMapDemo {
public static void main(String args[]) {
// Create a hash map
TreeMap tm = new TreeMap();
int indexDesired;
int visits;
String planetNameVariable;
String crewMemberName;
//Scan input using Scanner and assign planet name and crew name to
//correct variables (code provided by instructor)
// Put elements to the map
//if(planet doesn't already exist in tm)
tm.put(planetNameVariable, new int[14]);
//Decides which element of the array must be incremented
indexDesired = crewToIndex(crewMemberName);
//Increments visit count of crewMemberName on planetNameVariable
visits = //How do I get the value of the array associated with planetNameVariable at indexDesired?
tm.put(planetNameVariable, int[indexDesired] = visits + 1 //How do I insert into an array element here?);
// Get an iterator
Iterator i = set.iterator();
// Display element
// Code not designed yet
}
}
You can something like this. Here you have to put array in map only once because after that you will get only reference so if you modify that it will be modified in map as well.[shallow copy]
int visits[] = null;
// Increments visit count of crewMemberName on planetNameVariable
visits = tm.get(planetNameVariable);
if (visits == null) {
tm.put(planetNameVariable, new int[14]);
visits = tm.get(planetNameVariable);
}
visits[indexDesired]++;
// Get an iterator
Iterator<String> iterator = tm.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
int[] temp = tm.get(key);
if (temp != null) {
for (int i = 0; i < temp.length; i++) {
System.out.println(key + " " + temp[i]);
}
}
}
I have 3 arraylist each have size = 3 and 3 arrays also have length = 3 of each. I want to copy data from arraylists to arrays in following way but using any loop (i.e for OR for each).
myArray1[1] = arraylist1.get(1);
myArray1[2] = arraylist2.get(1);
myArray1[3] = arraylist3.get(1);
I have done it manually one by one without using any loop, but code appears to be massive because in future I'm sure that number of my arraylists and arrays will increase up to 15.
I want to copy the data from arraylists to arrays as shown in the image but using the loops not manually one by one?
How about this?
List<Integer> arraylist0 = Arrays.asList(2,4,3);
List<Integer> arraylist1 = Arrays.asList(2,5,7);
List<Integer> arraylist2 = Arrays.asList(6,3,7);
List<List<Integer>> arraylistList = Arrays.asList(arraylist0, arraylist1, arraylist2);
int size = 3;
int[] myArray0 = new int[size];
int[] myArray1 = new int[size];
int[] myArray2 = new int[size];
int[][] myBigArray = new int[][] {myArray0, myArray1, myArray2};
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
myBigArray[i][j] = arraylistList.get(j).get(i);
}
}
To explain, since we want to be able to work with an arbitrary size (3, 15, or more), we are dealing with 2-dimensional data.
We are also dealing with array and List, which are slightly different in their use.
The input to your problem is List<Integer>, and so we make a List<List<Integer>> in order to deal with all the input data easily.
Similarly, the output will be arrays, so we make a 2-dimensional array (int[][]) in order to write the data easily.
Then it's simply a matter of iterating over the data in 2 nested for loops. Notice that this line reverses the order of i and j in order to splice the data the way you intend.
myBigArray[i][j] = arraylistList.get(j).get(i);
And then you can print your answer like this:
System.out.println(Arrays.toString(myArray0));
System.out.println(Arrays.toString(myArray1));
System.out.println(Arrays.toString(myArray2));
You need to have two additional structures:
int[][] destination = new int [][] {myArray1, myArray2,myArray3 }
List<Integer>[] source;
source = new List<Integer>[] {arraylist1,arraylist2,arraylist3}
myArray1[1] = arraylist1.get(1);
myArray1[2] = arraylist2.get(1);
myArray1[3] = arraylist3.get(1);
for (int i=0;i<destination.length;i++) {
for (int j=0;j<source.length;j++) {
destination[i][j] = source[j].get(i);
}
}
If you cannot find a ready made API or function for this, I would suggest trivializing the conversion from List to Array using the List.toArray() method and focus on converting/transforming the given set of lists to a another bunch of lists which contain the desired output. Following is a code sample which I would think achieves this. It does assume the input lists are NOT of fixed/same sizes. Assuming this would only make the logic easier.
On return of this function, all you need to do is to iterate over the TreeMap and convert the values to arrays using List.toArray().
public static TreeMap<Integer, List<Integer>> transorm(
List<Integer>... lists) {
// Return a blank TreeMap if not input. TreeMap explanation below.
if (lists == null || lists.length == 0)
return new TreeMap<>();
// Get Iterators for the input lists
List<Iterator<Integer>> iterators = new ArrayList<>();
for (List<Integer> list : lists) {
iterators.add(list.iterator());
}
// Initialize Return. We return a TreeMap, where the key indicates which
// position's integer values are present in the list which is the value
// of this key. Converting the lists to arrays is trivial using the
// List.toArray() method.
TreeMap<Integer, List<Integer>> transformedLists = new TreeMap<>();
// Variable maintaining the position for which values are being
// collected. See below.
int currPosition = 0;
// Variable which keeps track of the index of the iterator currently
// driving the iteration and the driving iterator.
int driverItrIndex = 0;
Iterator<Integer> driverItr = lists[driverItrIndex].iterator();
// Actual code that does the transformation.
while (driverItrIndex < iterators.size()) {
// Move to next driving iterator
if (!driverItr.hasNext()) {
driverItrIndex++;
driverItr = iterators.get(driverItrIndex);
continue;
}
// Construct Transformed List
ArrayList<Integer> transformedList = new ArrayList<>();
for (Iterator<Integer> iterator : iterators) {
if (iterator.hasNext()) {
transformedList.add(iterator.next());
}
}
// Add to return
transformedLists.put(currPosition, transformedList);
}
// Return Value
return transformedLists;
}