I have a map TreeMap<Integer, Set<Integer>> adjacencyLists and an integer set TreeSet<Integer> specialNodes.
The map represents adjacency lists of a graph.
I want to pick keys from adjacencyLists and find if there is a common adjacent of them in specialNodes.
Is there a way to do this efficiently?
Example:
adjacencyLists is as follows:
[1, [2 3 4 5]]
[2, [1 5]]
[3, [1 4 5]]
[4, [1 3]]
[5, [1 2 3]]
and specalNodes is as follows:
[1 3 4 5]
In this example, 4 and 5 are present in the values of first and third entries of adjacencyLists.
Hence, writing a function findCommon(1,3) should give me [4 5]
Similarly, findCommon(1,5) should return null because '2' is the only element that is common and is not in specialNodes.
Here's a step by step procedure.
Get the two values from the keys. O(logn).
Sort them. O(nlogn).
Find the common elements. O(m+n).
Search for the common elements in specialNodes. O(m+n).
Hence worst case time complexity = O(nlogn).
So if I'm understanding correctly you already have a set for each Integer listing its adjacency?
The easiest efficient way I can see to do this is to make use of another Set. Sets are very fast for checking if they already contain values.
Set<Integer> adjacent = new HashSet<>();
for (Integer i: toCheck) {
int oldCount = adjacent.size();
Set<Integer> check = adjacencyLists.get(i);
adjacent.addAll(check);
if (adjacent.size() != oldCount+check.size()) {
// Duplicate found
return true;
}
}
return false;
If you need to know the identify of the common then loop through doing individual add calls instead of doing the addAll and check each add for success. This may actually be more efficient as no need to do the size checks:
Set<Integer> adjacent = new HashSet<>();
for (Integer i: toCheck) {
Set<Integer> check = adjacencyLists.get(i);
for (Integer c: check)
if (!adjacent.add(c)) {
// Duplicate found
return c;
}
}
return null;
Just saw the request for the full list of common members:
Set<Integer> adjacent = new HashSet<>();
Set<Integer> results = new HashSet<>();
for (Integer i: toCheck) {
Set<Integer> check = adjacencyLists.get(i);
for (Integer c: check)
if (!adjacent.add(c)) {
// Duplicate found
results.add(c);
}
}
return results;
Not 100% sure what you mean, but this is my idea. One possible way is to use a search algorithm like BFS. Since all those four nodes must have one common node, means if you use one of your four nodes as root and search for each other of the three nodes. If the search for all three is a successful they must have one common node.
The obvious solution would be to make a copy of specialNodes, then call its method retainAll on all the sets that you are considering, and the resulting set contains the common nodes. Did you try it ? Is it not efficient enough ?
Code:
Set findCommons(int a, int b) {
HashSet commonNodes = new HashSet(specialNodes);
commonNodes.retainAll(adjacencyLists.get(a));
commonNodes.retainAll(adjacencyLists.get(b));
return commonNodes;
}
Related
I was trying this problem where we need to find the permutations of the elements in the array.
This is the leetcode problem no 46. The issue I've faced is that I'm not able to output the ans it just keeps returning a blank ArrayLists:
Code:
public List<List<Integer>> permute(int[] nums)
{
List<List<Integer>> fans = new ArrayList<>();
HashMap<Integer, Integer> fmap = new HashMap<>();
for(int i: nums){
fmap.put(i, fmap.getOrDefault(i, 0) + 1);
}
int n=nums.length;
List<Integer> ans=new ArrayList<>(n);
dfs(1, n, fmap, ans, fans);
return fans;
}
public void dfs(int cs, int ts, HashMap<Integer, Integer> fmap,List<Integer> ans, List<List<Integer>> fans)
{
if (cs > ts)
{
fans.add(ans);
return;
}
for(Integer val: fmap.keySet())
{
if (fmap.get(val) > 0)
{
fmap.put(val, fmap.get(val) - 1);
ans.add(val);
dfs(cs + 1, ts, fmap, ans, fans);
ans.remove(ans.size() - 1);
fmap.put(val, fmap.get(val) + 1);
}
}
}
Output for the test case [0,1]:
[[],[]]
The actual output should be:
[[0,1],[1,0]]
When I'm checking the "potential answer" inside the recursive method, I am able to see the correct answer. I mean, if I print the output in the dfs method, it shows the correct answer:
Change in the code:
if (cs > ts)
{
fans.add(ans);
System.out.println(fans);
return;
}
Now it's printing the value of fans:
[[0, 1]]
[[1, 0], [1, 0]]
But these values are not being updated in the fans and the returned value comes up blank.
I read someone mention this same issue, but it was for Python, and the solution in that case was to do a deep copy of the list.
I'm not sure how to do that in Java.
What I'm doing wrong?
In order to generate a list of permutations, you don't need a Map. You've only introduced redundant actions, which are not useful anyhow. If you doubt, add a couple of print-statements to visualize the map state it will always contain the same key with the value 1 (all numbers in the input are guaranteed to be unique) and it has no impact on the result.
Source of data for generating the Permutations
Besides the fact that attempt to utilize the HashMap as the source of data for generating permutations isn't working because of the bugs, it's also not a good idea because the order iteration over the keySet of HashMap is not guaranteed to be consistent.
As the uniform mean for storing the numbers that haven't yet been applied in current permutation, we can use an ArrayList. In this case because there will be no duplicates in the input (see the quote from the leetcode below), we can use a LinkedHashSet instead to improve performance. As explained below, a removal of elements will happen at before making every recursive a call, and removal from an ArrayList has a cost of O(n), meanwhile with LinkedHashSet it would be reduced to O(1).
Constraints:
1 <= nums.length <= 6
-10 <= nums[i] <= 10
All the integers of nums are unique.
Generating the Permutations
Each generated permutation should be contained in its own list. In your code, you've created one single list which is being passed around during recursive calls and eventually every recursive branch adds the same list to the resulting list. Which obviously should not happen.
You see, the result is being printed as [[],[]]. It seems like a list containing two lists, but in fact they refer to the same empty list.
And this list is empty because every element that was added to it, is being removed after performing a recursive call:
ans.add(val);
... <- rursive call in between
ans.remove(ans.size() - 1); // removes the last element
if I print the output in the dfs method, it shows the correct answer:
Actually, it's not correct. If you take a careful look at the results, you'll see the nested lists are the same [[1, 0], [1, 0]].
The final result is blank because all recursive calls are happening between each value being added and removed (see the code snippet above). I.e. removal will be performed in revered order. That would be the last lines to be executed, not the return statements. To understand it better, I suggest you to walk through the code line by line and draw on paper all the changes done to the ans list for a simple input like [0, 1].
Instead, you should create a copy of the list containing not fully generated permutation (answer) and then add an element into the copy. So that the initial permutation (answer) remains unaffected and can be used as a template in all subsequent iterations.
List<Integer> updatedAnswer = new ArrayList<>(answer);
updatedAnswer.add(next);
And you also need to create a copy of the source of data and remove the element added to the newly created permutation (answer) in order to avoid repeating this element:
Set<Integer> updatedSource = new LinkedHashSet<>(source);
updatedSource.remove(next);
Sidenote: it's a good practice to give meaningful names to methods and variables. For instance, names cs and ts aren't informative (it's not clear what they are meant to store without looking at the code), method-name dfs is confusing, DFS is a well-known algorithm, which is used for traversing tree or graph data structures, but it's not related to this problem.
Building a recursive solution
It makes sense to keep the recursive method to be void to avoid wrapping the result with an additional list that would be thrown away afterwards, but in general it's more handy to return the result rather than accumulating it in the parameter. For performance reasons, I'll keep the method to be void.
Every recursive implementation should contain two parts:
Base case - that represents a simple edge-case (or a set of edge-cases) for which the outcome is known in advance. For this problem the base case would represent a situation when the given permutation has reached the size of the initial array, i.e. the source will contain no element, and we need to check whether it's empty or not. Parameters cs and ts that were used for this check in the solution provided in the question are redundant.
Recursive case - a part of a solution where recursive calls a made and when the main logic resides. In the recursive case, we need to replicate the given answer and source as explained above and use the updated copies as the arguments for each recursive call.
That's how it might be implemented:
public static List<List<Integer>> permute(int[] nums) {
Set<Integer> source = new LinkedHashSet<>();
for (int next: nums) source.add(next);
List<List<Integer>> result = new ArrayList<>();
permute(source, new ArrayList<>(), result);
return result;
}
public static void permute(Set<Integer> source, List<Integer> answer,
List<List<Integer>> result) {
if (source.isEmpty()) {
result.add(answer);
return;
}
for (Integer next: source) {
List<Integer> updatedAnswer = new ArrayList<>(answer);
updatedAnswer.add(next);
Set<Integer> updatedSource = new LinkedHashSet<>(source);
updatedSource.remove(next);
permute(updatedSource, updatedAnswer, result);
}
}
main()
public static void main(String[] args) {
int[] source = {1, 2, 3};
List<List<Integer>> permutations = permute(source);
for (List<Integer> permutation: permutations) {
System.out.println(permutation);
}
}
Output:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
A link to Online Demo
I have two lists, in one list values are 1,2,3
another list 2,3
I want to remove the values which are not matched in both lists.
2 and 3 are matched in both lists then 1 is not mached in both lists so I want to remove that value.
List original = [1,2,3];
List dummy = [2,3];
If it's possible to use sets instead, then you can just get the intersection between the sets (info):
Set<String> s1;
Set<String> s2;
s1.retainAll(s2); // s1 now contains only elements in both sets
Of course with sets you can't have duplicates and you'll lose ordering.
You don't need to use a Set to achieve your requirement.
Use retainAll() defined in Collection that any List implementation implements such as :
List<Integer> original = new ArrayList<>(Arrays.asList(1,2,3));
List<Integer> dummy = Arrays.asList(2,3);
original.retainAll(dummy);
System.out.println(original);
Output :
[2, 3]
If you are using Java 8+ you can use :
original.removeIf(a -> !dummy.contains(a));
Here is an example with Java 10
var original = new ArrayList<>(List.of(1, 2, 3, 4));
var dummy = new ArrayList<>(List.of(2, 4, 3));
original.removeIf(a -> !dummy.contains(a));
System.out.println(original);
->[2, 3, 4]
I need to provide a Java solution that given two list, a & b, that returns a value that is present in one list but not in another.
e.g.
lists a = [26, 13, 88, 9]
lists b = [26, 1, 8, 12]
for those kind of operation it would be better to use collections,
the method removeAll() will filter the data containers, from the doc:
Removes from this list all of its elements that are contained in the
specified collection (optional operation).
List<Integer> myVarListA = Arrays.asList(26, 13, 88, 9);
List<Integer> myVarListB = Arrays.asList(26, 1, 8, 12);
List<Integer> myVarListAcomplementB = new ArrayList<>(myVarListA);
List<Integer> myVarListBcomplementA = new ArrayList<>(myVarListB);
myVarListAcomplementB.removeAll(myVarListB);
myVarListBcomplementA.removeAll(myVarListA);
System.out.println("elements in A but no in B: " + myVarListAcomplementB);
System.out.println("elements in B but no in A: " + myVarListBcomplementA);
myVarListBcomplementA.addAll(myVarListAcomplementB);
System.out.println("both together: " + myVarListBcomplementA);
Simple solution is to calculate the intersection and remove that from the desired list. If you only want what is missing, you can optimize this a little by going a solution like ΦXocę 웃 Пepeúpa ツ.
The great thing about this solution is that you can easily expand this to use 3+ sets/lists. Instead of A-B = diff or A-I(A,B)=diff, you can also do A-I(A,I(B,C)) to find what A is missing from the common set between A, B and C.
public static <T> HashSet<T> intersection(Collection<T> a, Collection<T> b) {
HashSet<T> aMinusB = new HashSet<>(a);
aMinusB.removeAll(b);
HashSet<T> common = new HashSet<>(a);
common.removeAll(aMinusB);
return common;
}
Let's call the intersection set Collection I = intersection(a,b);.
Now if you want to find what is missing from list A that was in B:
new LinkedList(A).removeAll(I);//ordered and possibly containing duplicates
OR
new ArrayList(A).removeAll(I);//ordered and possibly containing duplicates. Faster copy time, but slower to remove elements. Experiment with this and LinkedList for speed.
OR
new LinkedHashSet<T>(a).removeAll(I);//ordered and unique
OR
new HashSet<T>(a).removeAll(I);//unique and no order
Also, this question is effectively duplicate of How to do union, intersect, difference and reverse data in java
You may try this:
a.removeAll(b);
Simply parse the second list and add unique elements to the first, delete others.
for (Integer elem : secondList)
if (firstList.contains(elem))
firstList.remove(elem);
else
firstList.add(elem);
In firstList you will have the values present only in one of the lists.
I am having a list in the format
ArrayList<Integer> list = new ArrayList();
where I add and remove various elements in a loop. However, I need some structure where I can store the temporary lists so that I can access them later.
So for example, if I do System.out.print(list) it will return
[1,2,3,4]
then I need to call something like store.add(list)
and then if I add another element to the list - list.add(5) it becomes
[1,2,3,4,5]
then again
store.add(list)
and by calling System.out.print(store) it should return
[1,2,3,4]
[1,2,3,4,5]
In other words, store should be something like list within list?
List in list creating like this: List<List<Integer>> listInList = new ArrayList<List<Integer>>();
I suppose you want to have multiple versions of the same list.
You can't get that by just having a List of List.
The list will store only reference to the member lists stored inside it. So when you edit your list, all older versions will be edited as well. It's the same list behind the scene.
The correct way to use the List<List<Integer>> would be as follows.
List<List<Integer>> store = new ArrayList<>(); // Create storage for versions
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4));
store.add(new ArrayList<>(list)); // Add list's copy to store.
list.add(5); // Edit it as you want.
store.add(new ArrayList<>(list)); // Add list's copy to store.
System.out.println(store); // Print all versions
Output:
[[1, 2, 3, 4], [1, 2, 3, 4, 5]]
Hope this helps.
It is somewhat wasteful to store every new list, especially when the changes to the previous are very simple (e.g. additions and deletions at/from the end). You could come up with a strategy of keeping track of changes rather than storing the same information repeatedly.
First, you should decide which of the following is more important:
Have the list of lists readily available, at the expense of memory. This is desirable when you know you will need it very often and therefore cannot afford the overhead of generating it on-the-fly from history.
Use space efficiently, at the occasional cost of computing the list of lists from history. This is desirable when you make many changes and use the list of lists rarely.
The solutions already posted address 1., so here is a proposal for 2. (I will restrict the possible operations to adding and removing from the rear for the sake of brevity):
public enum Operation { ADD, REMOVE }
public class Modification {
Operation operation;
Integer element;
public Modification(Operation operation, Integer element) {
this.operation = operation; // could add some sanity checks (e.g. cannot remove from empty list)
this.element = element;
}
}
List<Integer> initialList = Arrays.asList(1, 2, 3, 4);
List<Modification> history = new ArrayList<>();
history.add(new Modification(Operation.ADD, 5));
Then you can define a function to compute the list of lists that you need:
List<List<Integer>> getAllLists (List<Integer> initialList, List<Modification> history) {
List<List<Integer>> allLists = new ArrayList<>();
allLists.add(initialList);
prevList = initialList;
for (Modification modification : history) {
prevList = new ArrayList<>(prevList);
if (modification.operation == ADD) prevList.add(modification.element);
else prevList.remove(prevList.size()-1);
allLists.add(prevList);
}
return allLists;
}
Let's say I have a list (EG: LinkedList<SomeObject>that contains elements ordered by a certain attribute (EG: SomeObject.someValue()). This attribute can and usually does repeat often/it isn't unique, BUT is never null.
Is there a convenient way to divide this into multiple Lists, each list containing only its equal in cardinal order? Also, can this be done with only once iteration of the list? For example, the original list:
1, 1, 1, 2, 2, 3, 3, 3
The desired lists from this:
1, 1, 1
2, 2,
3, 3, 3
Not too convenient, but:
start a loop. Store the previous item, and compare it to the current.
if the previous is different from the current (using equals(..), and be careful with null), then create a new List, or use list.subList(groupStart, currentIdx)
You could use Apache CollectionUtils to do this, where "list" is the original list, and "value" is the current value of the objects you want to extract a sublist for:
Collection<SomeObject> selectedObjects = CollectionUtils
.select(list,
new Predicate() {
boolean evaluate(Object input) {
return ((SomeObject) input).someValue().equals(value);
}
});
This approach means using a well known and well tested library (which always is a good thing), but the downside is that you will loop through the list once for each sublist you need.
Pretty sure there isn't a java API method for this. However you can write:
// This assumes your list is sorted according to someValue()
// SomeValueType is the type of SomeObject.someValue()
public Map<SomeValueType, List<SomeObject>> partition(List<SomeObject> list) {
Object currValue = null;
HashMap<SomeValueType, LinkedList<SomeObject>> result = new HashMap<SomeValueType, LinkedList<SomeObject>>();
LinkedList<SomeObject> currList = null;
for (SomeObject obj : list) {
if (!obj.someValue().equals(currValue()) {
currValue = obj.someValue();
currList = new LinkedList<SomeObject>();
result.put(currValue, currList);
}
currList.add(obj);
}
}
This will return you an HashMap of sublists, where the key is the someValue and the value is the partitioned list associated to it. Note, I didn't test this, so don't just copy the code.
EDIT: made this return hashmap instead of arraylist.
If you would use Google Guava-libaries:
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
public class Example {
public static void main(String[] args) {
HashMultiset<Integer> ints = HashMultiset.create();
ints.addAll(Lists.newArrayList(1, 1, 1, 2, 2, 3, 3, 3));
System.out.println(ints);
}
}
Output:
[1 x 3, 2 x 2, 3 x 3]
If you need to count how many elements of x you have use ints.count(x);, if you have value types you do not need to have more then just count.
With Guava, use Multimaps.index(Iterable<V>, Function<? super V, K>).
This should work (untested, but I am pretty sure everything is ok, This also assumes that the contents of the list are sortable):
public static List[] getEquivalentSubLists( List parent )
{
List cloneList = parent.clone();
Collections.sort(cloneList);
ArrayList<List> returnLists;
int end;
while (cloneList.size() > 0)
{
end = cloneList.lastIndexOf(cloneList.get(0));
returnLists.add(cloneList.subList(0, end));
cloneList.removeAll(cloneList.subList(0, end));
}
return returnList.toArray();
}