Way to overcome fail-fast iterator in HashMap - java

In competitive programming, I was solving a given problem - given an array nums of non-negative integers, and a target sum S, we have to find out the number of ways we can obtain target sum from sum of given numbers (where each nums[i] can be taken as nums[i] or -nums[i].
Although I came across some solutions that mainly relied on direct access tables using array (it is given that sum of numbers cannot exceed 1000), but I tried it using HashMap to reduce the space required. My code is as follows -
public int findTargetSumWays(int[] nums, int S) {
Map<Integer, Integer> dp = new HashMap();
dp.put(nums[0], 1);
dp.put(-nums[0], dp.getOrDefault(-nums[0], 0) + 1);
for (int i=1; i<nums.length; i++) {
for (Integer sum : dp.keySet()) {
dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
dp.put(sum-nums[i], dp.getOrDefault(sum-nums[i], 0) + 1);
}
}
return dp.get(S);
}
But I am getting ConcurrentModificationException on running the code. I tried finding about the issue. Although I got some conceptual understanding that in iteration, view of Collections can't be structurally modified, I am not able to figure out how to find my way around it to find a solution.
Is it that a solution using HashMap(or any dynamic data structure) is not possible? Any help is appreciated.

for (Integer sum : dp.keySet()) {
dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
// ...
}
If sum + nums[i] isn't a key that's already in the map, this results in a structural modification of the map: that is, you're adding a new key/value pair.
As described in the Javadoc:
The iterators returned by all of this class's "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove method, the iterator will throw a ConcurrentModificationException.
(If the key were already in the map, you'd just be modifying the value associated with that key, and this would be fine).
The easiest way to get around this is to take a snapshot of the keys to iterate over, by copying the elements into e.g. a list:
for (Integer sum : new ArrayList<>(dp.keySet())) {
Now, you're iterating the list, not the map's keyset, so you are free to modifying the map structurally inside that loop.
Separately from the question of the exception, your put/getOrDefault lines would be more simply written as:
// dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
// becomes
dp.merge(sum+nums[i], 1, Integer::sum);

The reason for ConcurrentModificationException is that you are modifying the keys of dp while iterating dp.keySet() in the following loop:
for (Integer sum : dp.keySet()) {
dp.put(sum+nums[i], dp.getOrDefault(sum+nums[i], 0) + 1);
dp.put(sum-nums[i], dp.getOrDefault(sum-nums[i], 0) + 1);
}

Related

How to find next minimum in a hash map key?

I have a scenario where I have a map:
BiMap <Integer, String> map;
and a list which tracks the index which are processed.
List<Integer> filled;
While processing if the filled list contains the key then I should find the next min key from the map which is already not in the filled list.
Can some one tell me is there an easy way to do this without doing many iterations?
for (int i =0 ;i <size; i++) {
if(map.contiansKey(i)) {
Integer min = list.contains(i) ? getNextMinFrom(map, filled) : null;
if min != null ?System.out.println(map.get(min)) : continue;
}
}
For Eg:
Filled - 0, 4, 5, 6
Map - (1,dfs) (4,efs) (5,sdfs)
in the 0 th iteration.. output - dfs (1 is min)
in 4th iteration ... output shoudl be 4efs (4 is the next min)
....
The issue is I can not remove entries from the list.
use a TreeSet initialized with the 'KeySet' of your map and while you add Any key to filled remove it from 'TreeSet',as a result, the first element of TreeSet is what you want
Is this what you want to achieve? Start from the front of the filled array and go until you find the first value that is in filled but not in the map?
public int get smallestUnusedValue() {
for(int i = 0; i < filled.size(); i++)
if(!map.containsKey(filled.get(i)))
return i;
}
Do you need to use a HashMap specifically? Implementations of NavigableMap, such as TreeMap, provide methods to look up keys "adjacent to" a given value, without requiring an exact map. The higherEntry method seems to do what you want.

how to merge two sorted arrays of same size?

1st array: {3,5,6,9,12,14,18,20,25,28}
2nd array: {30,32,34,36,38,40,42,44,46,48}
Sample Output:
{3,5,6,9,12,14,18,20,25,28,30,32,34,36,38,40,42,44,46,48}
I have to merge 1st array into second array. 2nd array has space to accomadate all values
Whenever i know i need a collection to be sorted, i use a method that will insert new elements in right place, so the collection will never have state when its not sorted... in your case you might be good with adding two into destination collection then use Collections.sort() but you can do sortedInsert() as well... you can create your collection and start addin all items into it using this method, and when you finished you dont need another call to Collections.sort() because collection is always in sorted state... This is handy if you often do single element update and dont want whole collection to be resorted... this will work with much better performance...
Here is what i do for List
/**
* Inserts the value keeping collection sorted, provided collections shall be sorted with provided
* comparator
*/
public static <E> void sortedInsert(List<E> list, E value, Comparator<? super E> comparator) {
assert Ordering.from(comparator).isOrdered(list);
if (list.size() == 0) {
list.add(value);
} else if (comparator.compare(list.get(0), value) > 0) {
list.add(0, value);
} else if (comparator.compare(list.get(list.size() - 1), value) < 0) {
list.add(list.size(), value);
} else {
int i = 0;
while (comparator.compare(list.get(i), value) < 0) {
i++;
}
list.add(i, value);
}
}
Use System.arraycopy to append a1 to a2
System.arraycopy(a1, 0, a2, a2_len, a1.length);
then Arrays.sort
Use two pointers/counters, i & j starting from 0 to size of the array. Compare a[i] & b[j] and based on the result shift i or j (similar to merge sort, merging step). If extra space isn't allowed then in worst case (which is true in your input, all the elements in first array is smaller than first element in second array) you might have to shift 2nd array every time you compare elements.
Make a ArrayList object as arrayListObject
ArrayList<Integer> arrayListObject= new ArrayList<>();
Add elements of both arrays in that arrayListObject
Do Collectios.sort(arrayListObject) to sort the elements.
Use
Integer list2[] = new Integer[arrayListObject.size()];
list2 = arrayListObject.toArray(list2);
to get the resulted array

Getting the indices of an unsorted double array after sorting

This question comes as a companion of this one that regarded fastest sorting of a double array.
Now I want to get the top-k indices corresponding to the unsorted array.
I have implemented this version which (unfortunately) uses autoboxing and HashMap as proposed in some answers including this one:
HashMap<Double, Integer> map = new HashMap<Double, Integer>();
for(int i = 0; i < numClusters; i++) {
map.put(scores[i], i);
}
Arrays.sort(scores);
HashSet<Integer> topPossibleClusters = new HashSet<Integer>();
for(int i = 0; i < numClusters; i++) {
topPossibleClusters.add(map.get(scores[numClusters - (i+1)]));
}
As you can see this uses a HashMap with keys the Double values of the original array and as values the indices of the original array.
So, after sorting the original array I just retrieve it from the map.
I also use HashSet as I am interested in deciding if an int is included in this set, using .contains() method. (I don't know if this makes a difference since as I mentioned in the other question my arrays are small -50 elements-). If this does not make a difference point it out though.
I am not interested in the value per se, only the indices.
My question is whether there is a faster approach to go with it?
This sort of interlinking/interlocking collections lends itself to fragile, easily broken, hard to debug, unmaintainable code.
Instead create an object:
class Data {
double value;
int originalIndex;
}
Create an array of Data objects storing the original value and index.
Sort them using a custom comparator that looks at data.value and sorts descending.
Now the top X items in your array are the ones you want and you can just look at the value and originalIndex as you need them.
As Tim points out linking a multiple collections is rather errorprone. I would suggest using a TreeMap as this would allow for a standalone solution.
Lets say you have double[] data, first copy it to a TreeMap:
final TreeMap<Double, Integer> dataWithIndex = new TreeMap<>();
for(int i = 0; i < data.length; ++i) {
dataWithIndex.put(data[i], i);
}
N.B. You can declare dataWithIndex as a NavigableMap to be less specific, but it's so much longer and it doesn't really add much as there is only one implementation in the JDK.
This will populate the Map in O(n lg n) time as each put is O(lg n) - this is the same complexity as sorting. In reality it will be probably be a little slower, but it will scale in the same way.
Now, say you need the first k elements, you need to first find the kth element - this is O(k):
final Iterator<Double> keyIter = dataWithIndex.keySet().iterator();
double kthKey;
for (int i = 0; i < k; ++i) {
kthKey = keyIter.next();
}
Now you just need to get the sub-map that has all the entries upto the kth entry:
final Map<Double, Integer> topK = dataWithIndex.headMap(kthKey, true);
If you only need to do this once, then with Java 8 you can do something like this:
List<Entry<Double, Integer>> topK = IntStream.range(0, data.length).
mapToObj(i -> new SimpleEntry<>(data[i], i)).
sorted(comparing(Entry::getKey)).
limit(k).
collect(toList());
i.e. take an IntStream for the indices of data and mapToObj to an Entry of the data[i] => i (using the AbsractMap.SimpleEntry implementation). Now sort that using Entry::getKey and limit the size of the Stream to k entries. Now simply collect the result to a List. This has the advantage of not clobbering duplicate entries in the data array.
It is almost exactly what Tim suggests in his answer, but using an existing JDK class.
This method is also O(n lg n). The catch is that if the TreeMap approach is reused then it's O(n lg n) to build the Map but only O(k) to reuse it. If you want to use the Java 8 solution with reuse then you can do:
List<Entry<Double, Integer>> sorted = IntStream.range(0, data.length).
mapToObj(i -> new SimpleEntry<>(data[i], i)).
sorted(comparing(Entry::getKey)).
collect(toList());
i.e. don't limit the size to k elements. Now, to get the first k elements you just need to do:
List<Entry<Double, Integer>> subList = sorted.subList(0, k);
The magic of this is that it's O(1).

iterating through list in java using for loop

How does one iterate through a list datastructure using indices. For example consider a sentence in form a list with each element being a word. Can I step through each word using the index? Something like this --
// sentence defined something like this - List<String>
int size = sentence.size();
for (int i=0; i<size-1; i++)
{
System.out.println(sentence[i] + " " + sentence[i+1]);
}
ofcourse the above code doesn't work but is it possible to do something on those lines? As you can see, I want to access the two consecutive elements and using iterators, it starts becoming really messy.
You can use the get(i) method instead of [i]:
for (int i=0; i<size-1; i++) {
System.out.println(sentence.get(i) + " " + sentence.get(i+1));
}
List instances are not the same as arrays. They have specific methods for obtaining items at certain indexes. Try this:
// sentence defined something like this - List<String>
int size = sentence.size();
for (int i=0; i<size-1; i++)
{
System.out.println(sentence.get(i) + " " + sentence.get(i + 1));
}
Now if you had an array (e.g. String[] sentence = new String[]{"hello", "there"}), what you had would work fine.
As a side note, Java has a for-each loop that can be used on both arrays and Lists:
for (String s : sentence) {
// do something
}
Of course, this can't be used in your case because you're accessing elements at multiple indexes in each iteration of your loop - but it's important to know that something like this exists.
The x[i] expression syntax in Java can only be used for arrays. Nothing else.
As other answers have stated, the way to step through the elements of a Java list using indices is to use List.get(int). However, there is an important performance issue that needs to be considered when you do this.
The issue is that the cost of a get(int) call depends on what List implementation class you use:
For an ArrayList (or a Vector) the get(int) operation on a list of length N is O(1). That means that it does not depend on the list length, and in fact it is cheap: only a bit more expensive than an someArray[i].
For a LinkedList, the get(int) operation on a list has to step through the list from the beginning until it reaches the position you asked for. If the list length is N, then the average cost of get(int) (assuming a random position in the list) is O(N); i.e. it is proportional to the list length. If the length is long, then that will be expensive.
By contrast, if you use an Iterator (explicitly, or implicitly by using the for (E e : l) syntax), getting each element will be O(1) for all of the list implementations in java.util and java.util.concurrent (ignoring multi-threading issues such as heavy contention).
Having said that, there are some cases where iterators don't work, and the application needs to use indices.
You can also use Iterator in this case for ex:
first of all put ur elements on arraylist and try to use Iterator like this:
ArrayList arrayList = new ArrayList();
Iterator itr = arrayList.iterator();
while(itr.hasNext())
{
System.out.println(itr.next()); // Print out the elements from arraylist
}
You can process consecutive pairs of values from a list without using indices. Here's one way:
private void processWordsInSentence(List<String> sentence) {
Iterator<String> it = sentence.iterator();
if (it.hasNext()) {
String previous = it.next();
while(it.hasNext()) {
String current = it.next();
// use previous and current values, e.g.
System.out.println(previous + " " + current);
previous = current;
}
}
}
Why would you want to use something like this instead of sentence.get(index)? I would offer a couple of reasons:
In your sample, your processing is really concerned with consecutive
values from the list, not their positions. So there's no "value add"
to having to fiddle with the index explicitly.
Remember that List<T> is an interface with multiple
implementations. ArrayList<T> performs .get(index) in constant
time, but that same call on a LinkedList<T> requires time
proportional to the value of index. So there could be a real performance
consideration.
The processWordsInSentence implementation above does have to deal explicitly with the case of lists with less than two elements. The loop inside the guarding if can be written with a for statement, to separate traversal from processing the actual data a bit more aggressively, if you prefer that style.
private void processWordsInSentence(List<String> sentence) {
Iterator<String> it = sentence.iterator();
if (it.hasNext()) {
for (
String previous = it.next(), current = null;
it.hasNext();
previous = current
) {
// use previous and current values, e.g.
System.out.println(previous + " " + current);
}
}
}
Try this simple code :
List mobileSoftwares = new ArrayList();
mobileSoftwares.add("Android");
mobileSoftwares.add("IOS");
mobileSoftwares.add("Blackberry");
int size = mobileSoftwares.size();
for (int i = 0; i < size - 1; i++)
{
System.out.println(mobileSoftwares.get(i));
}

Find number of distinct elements in a linked list

I have a LinkedList that contains many objects. How can I find the number and frequency of the distinct elements in the LinkedList.
You can iterate the list with a for-each loop while maintaining a histogram.
The histogram will actually be a Map<T,Integer> where T is the type of the elements in the linked list.
If you use a HashMap, this will get you O(n) average case algorithm for it - be sure you override equals() and hashCode() for your T elements. [if T is a built-in class [like Integer or String], you shouldn't be worried about this, they already override these methods].
The idea is simple: iterate the array, for each element: search for it in the histogram - if it is not there, insert it with value 1 [since you just saw it for the first time]. If it is in the histogram already, extract the value, and re-insert the element - with the same key and with value + 1.
should look something like this: [list is of type LinkedList<Integer>]
Map<Integer,Integer> histogram = new HashMap<Integer, Integer>();
for (Integer x : list) {
Integer value = histogram.get(x);
if (value == null) histogram.put(x,1);
else histogram.put(x, value + 1);
}
A simpler variation of the histogram solution with a Guava Multiset:
Multiset<Integer> multiset = HashMultiset.create();
multiset.addAll(linkedList);
int count = multiset.count(element); // number of occurrences of element
Set<Integer> distinctElements = multiset.elementSet();
// set of all the unique elements seen
(Disclosure: I work on Guava.)
#amit's answer is good, but I want to share a slight variation (and can't format a block of code in comment - otherwise this would just be a comment). I like to make two passes, one to create the histogram elements and the second to populate them. This feels cleaner to me, although it may be less efficient.
Map<Integer,Integer> histogram = new HashMap<Integer, Integer>();
for (Integer n : list)
histogram.put(n, 0);
for (Integer n : list)
histogram.put(n, histogram.get(n) + 1);
The LambdaJ Library offers a few interesting methods to query collections very easily as well:
List<Jedi> jedis = asList(
new Jedi("Luke"), new Jedi("Obi-wan"), new Jedi("Luke"),
new Jedi("Yoda"), new Jedi("Mace-Windu"),new Jedi("Luke"),
new Jedi("Obi-wan")
);
Group<Jedi> byName = with(jedis).group(Groups.by(on(Jedi.class).getName()));
System.out.println(byName.find("Luke").size()); //output 3
System.out.println(byName.find("Obi-wan").size()); //ouput 2
i have just learned about HashSet. i have no idea about map yet. so let me suggest my solution base on HashSet.
for(String a:Linklist1){
if(Hashset1.add(a){
count++;
}
}
System.out.println(count);
hope this helps.

Categories