How to get max from an ArrayList that has more than one max? For example, if an ArrrayList contains max = 20 stored at index 2, 3 and 6, how do you get all that indicies?
The obvious way is to first get maximum value by Collections.max(), then collect indicies where items are equal to max:
public <T extends Comparable<? super T>> List<Integer> maxIndicies(List<T> input) {
if (input.isEmpty()) // avoid exception thrown by Collections.max() if input is empty
return Collections.emptyList();
final T max = Collections.max(input);
return IntStream.range(0, input.size())
.filter(i -> input.get(i).compareTo(max) == 0)
.boxed()
.collect(Collectors.toList());
}
Additionally, I'd like to propose another solution where iteration is performed only once. During iteration, you need to check two things for each item: 1) if it is greater than current max, set a new max and reset result list, 2) if it is equal to current max, add its index to result list:
public <T extends Comparable<? super T>> List<Integer> maxIndicies(List<T> input) {
T max = null;
List<Integer> res = new ArrayList<>();
for (int i = 0; i < input.size(); i++) {
T item = input.get(i);
if (max == null || item.compareTo(max) > 0) { // item > max => reset
res.clear();
max = item;
res.add(i);
} else if (item.compareTo(max) == 0) // item equals current max
res.add(i);
}
return res;
}
This won't give you value of max item itself, but you can get it by any returned index, simply as:
List<Integer> maxInd = maxIndicies(list);
maxValue = maxInd.isEmpty() ? null : list.get(maxInd.get(0));
This sounds like a homework for your programming course. You should do it yourself but anyway here is the solution.
private List<Integer> getAllMaxIndices(List<Integer> aList) {
List<Integer> result = new ArrayList<Integer>();
// check argument
if (aList == null || aList.isEmpty()) {
return result;
}
// initialize the list with the index of the first element
result.add(0);
Integer tmpInt;
Integer tmpFirstIndexOfMaxInt;
Integer tmpMaxInt;
for (int i = 0; i < aList.size(); i++) {
// save the current integer and the currently maximum integer
tmpInt = aList.get(i);
tmpFirstIndexOfMaxInt = result.get(0);
tmpMaxInt = aList.get(tmpFirstIndexOfMaxInt);
// if the current element is greater than the last found
if (tmpInt > tmpMaxInt) {
// empty the result
result.clear();
// start collecting indices again
result.add(i);
}
// if the current element is equal to the last found
else if (tmpInt.intValue() == tmpMaxInt.intValue()) {
// insert the current index in the result
result.add(i);
}
}
return result;
}
I will leave it to you to write the code which tests this function.
Another approach using streams. That solution assumes that you want to know how often the max occurs (not the indices).
public static Map.Entry<Integer, Long> getMaxWithOccurrences(
List<Integer> list) {
return list
.stream()
.collect(
Collectors.groupingBy(i -> i, TreeMap::new,
Collectors.counting())).lastEntry();
}
I'd use a simple and easy to read for loop.
public List<Integer> getMaxIndices(List<Integer> values) {
Integer max = Collections.max(values);
List<Integer> maxIndices = new ArrayList<>();
for (int i = 0; i < values.size(); i++) {
if (values.get(i).equals(max)) {
maxIndices.add(Integer.valueOf(i));
}
}
return maxIndices;
}
Integer maxValue = Collections.max(list);
int numberofMax = Collections.frequency(list, maxValue);
this "numberofMax" will return how many maximum values the "list" has.
usual max finders only store the maximum met value, here you will have to maintain a list of indexes matching the maximum value.
You can do it in following way:
public void findMaxIndices() {
//Your list with numbers
List<Integer> list = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9));
//Sorted Map which will contain key as numbers and value as list of indices where your 'key' exists in the list
SortedMap<Integer, List<Integer>> indexMapping = new TreeMap<Integer, List<Integer>>();
for(int i = 0; i< list.size(); i++) {
//Get the number at index i
int number = list.get(i);
//Check if any index corresponding to 'number' as index has been added to your map
List<Integer> mapping = indexMapping.get(number);
if(mapping == null) {
//instantiate the list if no index has been added yet
mapping = new ArrayList<Integer>();
//Key as your 'number'
indexMapping.put(number, mapping);
}
//Add the index of the 'number' to the mapping list, which is mapped by key as 'number'
mapping.add(i);
}
//Last key in sorted map will be your highest number in the list, get the value corresponding to it. Following prints: [8,17]
int maxNumber = indexMapping.lastKey(); //Maximum number found
System.out.println(indexMapping.get(maxNumber)); //Indices where maximum number exists
}
This way, you can also find indices with lowest values easily:
indexMapping.get(indexMapping.firstKey());
Related
I used a HashMap to store the occurrences of each element, and then iterated over the hash map to get duplicated element, but something doesn't feel right about this solution.
Problem statement in Firecode.io:
Write a method duplicate to find the repeated or duplicate elements in an array. This method should return a list of repeated integers in a string with the elements sorted in ascending order (as illustrated below).
duplicate({1,3,4,2,1}) --> "[1]"
duplicate({1,3,4,2,1,2,4}) --> "[1, 2, 4]"
Note: You may use toString() method to return the standard string representation of most data structures, and Arrays.sort() to sort your result.*
Here is my code:
public String duplicate(int[] numbers) {
HashMap < Integer, Integer > hs = new HashMap < Integer, Integer > ();
for (int i = 0; i < numbers.length; i++) {
if (hs.get(numbers[i]) == null) {
hs.put(numbers[i], 1);
} else hs.put(numbers[i], (Integer) hs.get(numbers[i]) + 1);
}
int size = 0;
for (int i: hs.keySet()) {
if (hs.get(i) > 1) {
size++;
}
}
int j = 0;
int[] a = new int[size];
for (int i: hs.keySet()) {
if (hs.get(i) > 1) {
a[j++] = i;
}
}
Arrays.sort(a);
return Arrays.toString(a);
}
Here's the way I would do it: (comments for educational purposes, would probably not have them in production code.)
public String duplicate(int[] numbers) {
// holds the items we've encountered more than once.
// TreeSet<> keeps things in sorted order for us.
final SortedSet<Integer> duplicates = new TreeSet<>();
// keeps track of items we've encountered.
final Set<Integer> encountered = new HashSet<>();
// iterate over every number
for (final int number : numbers) {
// Add the item to encountered. Set.add() will return true if
// the element is new to the set.
if (!encountered.add(number)) {
// Since the element wasn't new, ensure this item exists in the duplicates collection.
duplicates.add(number);
}
}
return duplicates.toString();
}
Since you don't have to tell how many times an element is duplicated you only need a Set to remember which elements are unique and which not. If you know the element values (e.g. numbers between 1 and 10) you could further simplify Set to boolean[] or a bit vector:
int[] numbers = {1, 3, 4, 2, 2, 1, 2, 4, 4};
Set<Integer> unique = new HashSet<>();
Set<Integer> duplicates = new HashSet<>();
for (int n : numbers) {
if (!unique.add(n)) {
duplicates.add(n);
}
}
List<Integer> result = new ArrayList<>(duplicates);
result.sort(Integer::compareTo);
System.out.println(result); // [1, 2, 4]
If you are using Java 8 or beyond you can try:
public String duplicate(int[] numbers) {
Map<Integer, Integer> hs = new HashMap<>();
for ( int i : numbers ) {
hs.merge( i, 1, Integer::sum);
}
return '[' +
hs.entrySet()
.stream()
.filter( e -> e.getValue() > 1 )
.map(Entry::getKey)
.sorted()
.map(i -> i.toString())
.collect(Collectors.joining(", ")) +
']';
}
I have an array containing some duplicate elements like this :
find the first duplicate number for which the second occurrence has the minimal index. In other words, if there are more than 1 duplicated numbers, return the number for which the second occurrence has a smaller index than the second occurrence of the other number does. If there are no such elements, return -1
For a = [2, 1, 3, 5, 3, 2], the output should be
firstDuplicate(a) = 3.
There are 2 duplicates: numbers 2 and 3. The second occurrence of 3 has a smaller index than the second occurrence of 2 does, so the answer is 3.
I tried this :
int firstDuplicate(int[] a) {
Set<Integer> set = new HashSet<>();
Map<Integer, Integer> hm = new HashMap<Integer,Integer>();
Map.Entry<Integer, Integer> min = null;
for(int i=0;i<a.length;i++){
// if(!hm.containsKey(a[i]))
hm.put(a[i],i);
}
for(Map.Entry<Integer,Integer> entry : hm.entrySet()){
if(min == null || entry.getValue() < min.getValue()){
min = entry;
}
}
return min == null ? new Integer(-1) : min.getKey();
}
It's not working out, but I got another solution online which is like this :
int firstDuplicate(int[] a) {
Set<Integer> set = new HashSet<>();
Map<Integer, Integer> hm = new HashMap<Integer,Integer>();
Map.Entry<Integer, Integer> min = null;
for(int i=0;i<a.length;i++){
if(set.add(a[i])==false && !hm.containsKey(a[i]))
hm.put(a[i],i);
}
for(Map.Entry<Integer,Integer> entry : hm.entrySet()){
if(min == null || entry.getValue() < min.getValue()){
min = entry;
}
}
return min == null ? new Integer(-1) : min.getKey();
}
Can anyone please explain me the use of Hashset here, as it doesn't allow the duplicates so how that if condition will be workable.
The reason your first attempt failed is that you add the array elements as keys to the Map without checking if they are already there, which means you can't know if there are any duplicates by the time you finish populating the Map.
The alternative code you found does something different. It uses the Set to determine if the current array element already appeared earlier in the array, and if that's the case, it adds it as key to the Map only if it's not already there. This means that the Map will only contain elements that appear multiple times in the array, and the index associated with each element is the occurrence of the first duplicate. I.e. for the array {2, 1, 3, 5, 3, 2}, the Map will contain {2=5, 3=4}. Then it will return the key having the smallest value (which corresponds with the index of the first duplicate).
However, the Map is unnecessary, since you only need to find one duplicate, not all of them. Use the Set to locate the first duplicate and return it:
int firstDuplicate(int[] a)
{
Set<Integer> set = new HashSet<>();
for(int i=0;i<a.length;i++){
if(!set.add(a[i])) {
return a[i];
}
}
return -1; // no duplicates found
}
This relies on set.add() returning false if the Set already contains the element you wish to add. Once it returns false for the first time, you found the first duplicate.
I would strongly recommend you to try this to get the correct results
you can make it more efficient time complexity O(n)
int firstDuplicate(int[] a){
int n = a.length;
for(int i=0; i<n; i++)
{
if(a[Math.abs(a[i])-1]<0) return Math.abs(a[i]);
else a[Math.abs(a[i])-1] = - a[Math.abs(a[i])-1];
}
return -1;
}
int firstDuplicate(int[] a){
int n = a.length;
for(int i=0; i<n; i++)
{
if(a[Math.abs(a[i])-1]<0) return Math.abs(a[i]);
else a[Math.abs(a[i])-1] = - a[Math.abs(a[i])-1];
}
return -1;
}
I will explain why and how this one works.
It's important that this constrain: 1 ≤ a[i] ≤ a.length is present, meaning that in an array like this: a = [2,8,2] this algorithm WILL NOT work because 8 is bigger than a.length in this case 3.
You'll find the explanation here as well:
Hashmap
This solution follows the idea of a hashmap. Another structure where you count hash[arr[i]-1]++ the number of occurrences for any given index i in the array. Example:
If you have arr[2,1,3,5,3,2] hashmap will begin in an 6 zero array: hashmap[0,0,0,0,0,0] because that's the size of arr. As the algorithm progress it will sum +1 in the position arr[i]-1. It's using the value as the index of the sum. At then end you get: arr[1,2,2,0,1,0].
This has O(n) in time complexity because it runs the full arr, and O(n) in time because it runs the array at least 1 time.
Without Hashmap
The idea of the algorithm above is that you don't need the extra structure of a hashmap but can use the same array to count the frequency. This might lead to a problem. Let i-th element be a or (arr[i]=a) then the count should be stored at arr[arr[i]-1] or (arr[a-1]), but when the frequency will be stored the element will be lost.
Example iteration:
a[2,1,3,5,3,2] -> a[2,1,3,5,3,2]
a[2,1,3,5,3,2] -> a[1,1,3,5,3,2]
a[1,1,3,5,3,2] -> a[1,1,1,5,3,2]
a[1,1,1,5,3,2] -> a[1,1,1,5,1,2] As you can see we lost the value of 3 when we read 5 as it stored the frequency in arr[arr[4]-1] or (arr[5-1]).
Solve the missing problem
To solve this problem first we put replace the i-th element with arr[arr[i]-1] or (arr[a-1]) then put -1 at array arr[arr[i]-1] or (arr[a-1]).
The algorithm:
Traverse the array from start to end.
For each element check if the element is less than or equal to zero or not. If negative or zero skip the element as it is frequency.
If an element (a = arr[i] – 1) is positive, then check if arr[a] is positive or not. If positive then that means it is the first occurrence of a in the array and replace arr[i] with arr[a], and assign arr[a] = -1. If arr[a] is negative, then it is not the first occurrence, then update arr[a] as arr[a]-- and update arr[i] as arr[i] = 0. You use an auxiliary value to save arr[a] that will be used in the next iteration.
Again, traverse the array and print i+1 as value and arr[i] as frequency.
Example iteration:
a[2,1,3,5,3,2] -> a[1,1,3,5,3,2] -> a[1,-1,3,5,3,2]
a[1,-1,3,5,3,2] -> a[1,-1,3,5,3,2] -> a[1,-1,-1,5,3,2]
a[1,-1,-1,5,3,2] -> a[1,-1,-1,0,3,2]
a[1,-1,-1,0,3,2] -> a[1,-1,-1,0,-1,2] -> a[1,-1,-2,0,-1,2]
a[1,-1,-2,0,-1,2] -> a[1,-1,-2,0,-1,0]
a[1,-1,-2,0,-1,0] -> a[1,-2,-2,0,-1,0]
firstDuplicate
After knowing this we can now grasp how firstDuplicate works. The idea is not to count the frequency but instead just print the index that has already a negative in frequency. When we get a negative frequency we return.
So running the algorithm we get:
With if(a[2-1]<0) or if(1<0) this comparation is between arr[arr[0]-1] or (arr[1]) and 0 so we don't return. a[2,1,3,5,3,2] -> a[2,-1,3,5,3,2]
With if(a[1-1]<0) or if(2<0) we don't return a[2,-1,3,5,3,2] -> a[-1,-1,3,5,3,2].
With if(a[3-1]<0) or if(3<0) we don't return. a[-1,-1,3,5,3,2] -> a[-2,-1,-3,5,3,2]
With if(a[5-1]<0) or if(3<0) we don't return. a[-2,-1,-3,5,3,2] -> a[-2,-1,-3,5,-3,2]
With if(a[3-1]<0) or if(-3<0) we return.
All of this is based on the idea that element-1 is the index.
You can use java 8 with lambda and stream.
Here is the code in one line :
Set<Integer> allItems = new HashSet<>();
Arrays.stream(a).filter(i -> !allItems.add(i)).findFirst().orElse(-1)
it returns what you expect
There are two ways to implement this problem, by using a HashSet with time complexity o(n) and by using nested loops o(n2)
for(int i = 0; i < a.length; i++){
for(int j = i +1; j < a.length; j++){
if(a[i] == a[j]){
System.out.println(a[i]);
return;
}
}
}
Or you can make it more efficient time complexity O(n)
int index -1;
Set<Integer> hashSet = new HashSet<Integer>();
for(int i = a.length-1; i >= 0; i--){
if(hashSet.contains(a[i])){
index = i;
}else{
hashSet.add(a[i]);
}
}
System.out.println(a[index]);
int firstDuplicate(int[] a)
{
int DupIndex = 0;
int DupValue = 0;
for (int i = 0; i < a.Length; i++)
{
for (int j = i + 1; j < a.Length; j++)
{
if (a[i] == a[j])
{
if (j < DupIndex)
{
DupIndex = j;
DupValue = a[i];
}
else if (DupIndex == 0)
{
DupIndex = j;
DupValue = a[i];
}
}
};
};
return (DupValue == 0) ? -1 : DupValue;
}
public static void main(String[] args){
int array[]={2, 1, 3, 5, 3, 2};
int tempArray[]=new int[array.length];
int index=0;
while(index< array.length){
if(++(tempArray[array[index]])==2)
break;
index++;
}
if(index> array.length){
System.out.println("No Duplicate");
}else {
System.out.println("First Duplicate " + array[index]);
}
}
Use counting sort, sweet and simple :)
Java implementation
Time complexity O(n) -- Linear
Space Complexity O(n) -- Linear
//Approach
//run a loop and try to insert it into a map.
//check if map contains key for arr[nextValue]
//if contains key, break loop and return value.
//if not, keep on adding in the map.
import java.util.HashMap;
import java.util.Map;
public class ReturnFirstRecurringCharacter {
public static void main(String[] args) {
int[] arr1 = {2,5,5,2};
Integer recurringNumber = checkForRecurringNumber(arr1);
if (recurringNumber != null) {
System.out.println(recurringNumber);
} else {
System.out.println("Undefined");
}
}
private static Integer checkForRecurringNumber(int[] arr1) {
try {
if (arr1 != null) {
Map<Integer, Integer> dataMap = new HashMap<>();
for (int i = 0; i < arr1.length; i++) {
if (dataMap.containsKey(arr1[i])) {
return arr1[i];
}
dataMap.put(arr1[i], i);
}
}
} catch (Exception e) {
System.out.println(e);
e.getStackTrace();
}
return null;
}
}
JS solution:
function solution(a) {
const map = {};
for(let i=0; i<a.length; i++) {
if(map[a[i]]) {
if(map[a[i]][0] === 1) {
map[a[i]][0]++ ;
map[a[i]][1] = i;
}
} else {
map[a[i]] = [1, i];
}
}
const data = Object.keys(map).filter(key => map[key][0] == 2).map(el => parseInt(el));
let smallest = Infinity;
let smallestData = -1;
for(let i=0; i<data.length; i++) {
if(map[data[i]][1] < smallest) {
smallest = map[data[i]][1];
smallestData = data[i];
}
}
return smallestData;
}
Solution in Javascript
function solution(a) {
let i = -1;
while (++i < a.length)
if (a.indexOf(a[i]) !== i)
return a[i];
return -1;
}
console.log(solution([2, 1, 3, 5, 3, 2])); // 3
console.log(solution([2, 2])); // 2
console.log(solution([2, 4, 3, 5, 1])); // -1
I know how to find the highest value and index in a array(list). But I dont know how to get the indexes if there are multiple highest values in a array. I want to create a method/function that can two things: fill the array(list) with only one index if there is only one highest value, or create a arraylist if there are multiple highest values. For example I give two array's:
Array1={42,3,42,42,42,5,8};
I want to get the all the indexes of value 42 in a new array(list).
Array2={42,3,35,67};
I want to create a array(list) with only one index of value 42.
Try this for multiple indexes
List<Integer> list = new ArrayList<>();
int array[] = {1,1,2,4,5,3,1,5};
int max = array[0];
list.add(0);
for(int i=1;i<array.length;i++){
if(max<array[i]){
max = array[i];
list.clear();
list.add(i);
}else if(max==array[i])
list.add(i);
}
System.out.println(list);
For single index, use an extra variable, to store it it.
Using Java 8 features and assuming the array is not empty:
int maxValue = Arrays.stream(array)
.max()
.getAsInt();
int[] maxIndexes = IntStream.range(0, array.length)
.filter(i -> array[i] == maxValue)
.toArray();
That's 2 iterations where first you find the max value and then the indexes where an array element is equal to the max value.
Some documentation if you are not familiar with some classes/methods above:
IntStream, toArray(), getAsInt()
Depending on your scenario, having a small data set or a large data set, you might want to process the items sequentially or in parallel.
NOTE: the following code contains JUnit #Test annotation and AssertJ assertions.
Solution: sequential, one pass, small data set
This solution parses the array and keeps track of maximum and current maximum indexes. If a new maximum is found the indexes are cleared and the new maximum indexes are inserted.
#Test
public void sequential_algorithm_return_max_with_indexes() {
int[] values = new int[]{42, 3, 42, 42, 42, 5, 8};
int maxValue = Integer.MIN_VALUE;
List<Integer> maxValueIndexes = new ArrayList<>();
for (int index = 0; index < values.length; index++) {
int value = values[index];
if (value == maxValue) {
maxValueIndexes.add(index);
} else {
if (value > maxValue) {
maxValue = value;
maxValueIndexes.clear();
maxValueIndexes.add(index);
}
}
}
assertThat(maxValue).isEqualTo(42);
assertThat(maxValueIndexes).containsExactly(0, 2, 3, 4);
}
Solution: parallel, large data set
Streams are flexible and allow parallel processing.
Bellow data is represented as a pair of index-value instead of an array. This is done in order to transform the array of pairs into a stream and keep track of indexes.
Because this supposed to work in parallel, reduce method accepts 3 arguments - initial value, accumulator and combiner. This means that multiple buckets run in parallel. For each bucket there is an initial value and an accumulator used to process items sequentially. Then the parallel results of buckets are combined using the combiner argument.
#Test
public void parallel_algorithm_return_max_with_indexes() {
Pair<Integer, Integer>[] values = new Pair[]{
new Pair<>(0, 42),
new Pair<>(1, 3),
new Pair<>(2, 42),
new Pair<>(3, 42),
new Pair<>(4, 42),
new Pair<>(5, 5),
new Pair<>(6, 8),
};
ValueIndexes<Integer> maxValueIndexes = Arrays.stream(values)
.parallel()
.reduce(
new ValueIndexes<>(Integer.MIN_VALUE),
(ValueIndexes<Integer> valueIndexes, Pair<Integer, Integer> value) -> {
if (valueIndexes.getValue() == value.getValue()) {
valueIndexes.addIndex(value.getKey());
} else {
if (value.getValue() > valueIndexes.getValue()) {
valueIndexes = new ValueIndexes<>(value.getValue());
valueIndexes.addIndex(value.getKey());
}
}
return valueIndexes;
},
(valueIndexes1, valueIndexes2) -> {
if (valueIndexes1.getValue() == valueIndexes2.getValue()) {
ValueIndexes<Integer> valueIndexes = new ValueIndexes<>(valueIndexes1.getValue());
valueIndexes.addIndexes(valueIndexes1.getIndexes());
valueIndexes.addIndexes(valueIndexes2.getIndexes());
return valueIndexes;
} else {
if (valueIndexes1.getValue() > valueIndexes2.getValue()) {
return valueIndexes1;
} else {
return valueIndexes2;
}
}
}
);
assertThat(maxValueIndexes.getValue()).isEqualTo(42);
assertThat(maxValueIndexes.getIndexes()).containsExactlyInAnyOrder(0, 2, 3, 4);
}
private class ValueIndexes<T> {
private T value;
private List<Integer> indexes = new ArrayList<>();
public ValueIndexes(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public Iterable<Integer> getIndexes() {
return indexes;
}
public void addIndexes(Iterable<Integer> indexes) {
indexes.forEach(this::addIndex);
}
public void addIndex(int index) {
indexes.add(index);
}
}
I have a NavigableSet and I would like to get its median object.
Being that it's a NavigableSet, I know it's sorted, and thus I know that the median of it is either the middle element, or the arithmetic middle of the two middle elements.
Therefore I would like to access the element at set.size() / 2, but the NavigableSet interface doesn't allow me to.
Is there an easy way to get the specific element without having to iterate through the set manually?
Yes set does not allow you to get an element from a particular index. But I think if you convert it to an array then you will be able to achieve what you need. I tried this sample code, see if it helps:
NavigableSet set = new TreeSet<Integer>();
set.add(new Integer(5));
set.add(new Integer(4));
set.add(new Integer(3));
set.add(new Integer(2));
set.add(new Integer(1));
Integer medianIndex = set.size()/2;
System.out.println(set.toArray()[medianIndex]);
Output: 3
Strings are ordered alphabetically, have a look at this small example:
Edit: Now it really does what you wanted.
public static void main(String[] args) {
NavigableSet<String> set = new TreeSet<String>();
set.add("gamma");
set.add("alpha");
set.add("beta");
System.out.println(Arrays.toString(set.toArray()));
int indexOfGamma = set.headSet("gamma").size();
System.out.println(indexOfGamma);
System.out.println(get(set, set.first(), indexOfGamma));
}
public static String get(NavigableSet<String> set, String e, int index) {
if (index == 0) {
return e;
}
return get(set, set.higher(e), --index);
}
This is the output:
[alpha, beta, gamma]
2
gamma
I didn't do any benchmarks with greater data-sets, but I guess it should perform quite decent. The higher() method should directly point to the next element in the tree.
I haven't been able to find any way other than iterating through the set "index" number of times. However, since we know the size of the set, we can speed that up to at least half the size by using both ascending and descending iteration:
public static <T> T getInNavigableSetByIndex(NavigableSet<T> set, int index) {
Objects.requireNonNull(set);
final int size = set.size();
if (index < 0 || index >= size) {
throw new IndexOutOfBoundsException();
}
final boolean descend = index >= size / 2;
final Iterator<T> itr = descend ? set.descendingIterator() : set.iterator();
final int stepCount = descend ? size - index : index + 1;
T object = null;
for (int i = 0; i < stepCount && itr.hasNext(); i++) {
object = itr.next();
}
return object;
}
I'm trying to count how many duplicate items are in an array.
Example:
[0, 2, 0] would return 2, [0, 0, 0] would return 3, [0, 1, 2] = 0
So far I have it working for when all three items are equal, but I'm not sure why it's returning one less than what it should for 2 items being the same.
int equal = 0;
for(int i = 0; i < recent.length; i++) {
for(int j = i; j < recent.length; j++) {
if(i != j && recent[i].equals(recent[j])) {
equal++;
}
}
}
Your algorithm is flawed in the following way: for every element in the array you look at all the elements after that element and if they happen to be equal, you increase the counter. However when you have 3 same elements, you count the last one twice - when you run internal loop for first and for second element. Moreover you never count the first element.
So it works by accident for [0, 0, 0] but doesn't work for other inputs.
I think that having nested loops is quite inefficient. You should be able to do it in o(n) rather than o(n^2).
If you time yours against the following...
public void run() {
int[] array = createRandomArray(2000000, 1000000);
System.out.println(countNumDups1(array));
}
private int[] createRandomArray(int numElements, int maxNumExclusive) {
int[] array = new int[numElements];
Random random = new Random();
for (int i = 0; i < array.length; i++) {
array[i] = random.nextInt(maxNumExclusive);
}
return array;
}
private int countNumDups1(int[] array) {
Map<Integer, Integer> numToCountMap = new HashMap<>();
for (int i = 0; i < array.length; i++) {
Integer key = array[i];
if (numToCountMap.containsKey(key)) {
numToCountMap.put(key, numToCountMap.get(key) + 1);
}
else {
numToCountMap.put(key, 1);
}
}
int numDups = 0;
for (int i = 0; i < array.length; i++) {
Integer key = array[i];
if (numToCountMap.get(key) > 1) {
numDups++;
}
}
return numDups;
}
I think you'll find the above is much faster even considering the horrible inefficiency of autoboxing and object creation.
The code you gave counts equivalences, so it adds one every time an element equals another element.
It sounds like what you want is the number of duplicate items, which is the same as (length - number of items that don't have a duplicate). I will call the latter "uniqueItems".
I would recommend the following:
// set of every item seen
Set<Integer> allItems = new HashSet<Integer>();
// set of items that don't have a duplicate
Set<Integer> uniqueItems = new HashSet<Integer>();
for(int i = 0; i < recent.length; i++) {
Integer val = i;
if(allItems.contains(val)) {
// if we've seen the value before, it is not a "uniqueItem"
uniqueItems.remove(val);
} else {
// assume the value is a "uniqueItem" until we see it again
uniqueItems.add(val);
}
allItems.add(val);
}
return recent.length - uniqueItems.size();
The below code works perfectly to find the duplicates
int array[] = {1,2,3,4,5,2,3,4,5,3,4,5,4,5,5};
HashMap<Integer,Integer> duplicates = new HashMap<Integer,Integer>();
for(int i=0; i<array.length; i++)
{
if(duplicates.containsKey(array[i]))
{
int numberOfOccurances = duplicates.get(array[i]);
duplicates.put(array[i], (numberOfOccurances + 1));
}else{
duplicates.put(array[i], 1);
}
}
Iterator<Integer> keys = duplicates.keySet().iterator();
System.out.print("Duplicates : " );
while(keys.hasNext())
{
int k = keys.next();
if(duplicates.get(k) > 1)
{
System.out.print(" "+k);
}
}
You are counting the number of pairs of indices that have equal values. What you claim to want is the total size of all sets of equal elements that have more than one element in them.
I would use a Map or similar to count the total number of appearances of a given value. At the end, iterate over the key values adding the number of appearances for each key that has more than one appearance.
int intArray[] = {5, 1, 2, 3, 4, 5, 3, 2};
String val = "";
int c = 1;
Map<Integer, Integer> nwmap = new HashMap<Integer, Integer>();
for (int i = 0; i < intArray.length; i++) {
Integer key = intArray[i];
if(nwmap.get(key) != null && nwmap.containsKey(key)){
val += " Duplicate: " +String.valueOf(key)+"\n";
}else{
nwmap.put(key, c);
c++;
}
}
LOG.debug("duplicate value:::"+val);
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
public class ArrayDuplicateCount {
/**
* #author:raviteja katari
*/
public static void main(String[] args) {
int intArray[] = {5, 1,4,4,4,5,1,2,1,2,5,5};
//for counting duplicate items
int c = 0;
//creating map collection to hold integers as keys and Cont as value
Map<Integer, Integer> nwmap = new LinkedHashMap<Integer, Integer>();
for (int i = 0; i <intArray.length; i++) {
//Assigning array element to key
Integer key = intArray[i];
//this code checks for elemnt if present updates count value else
//put the new Array elemnt into map and increment count
if(nwmap.containsKey(key)){
//updating key value by 1
nwmap.put(key, nwmap.get(key) + 1);
}else{
//Adding new array element to map and increasing count by 1
nwmap.put(key, c+1);
}
}
//printing map
System.out.println(nwmap);
}
}
output:
{5=4, 1=3, 4=3, 2=2}
public void TotalduplicateNumbers {
int a[] = {2,8,2,4,4,6,7,6,8,4,5};
Map<Integer,Integer> m = new HashMap<Integer,Integer>();
for(int i=0;i<a.length;i++){
if(!m.containsKey(a[i]))
{
m.put(a[i], 1);
}
else
{
m.put(a[i], (m.get(a[i])+1));
}
}
for(Integer i:m.keySet()){
System.out.println("Number "+i+" "+"Occours "+m.get(i)+" time,");
}
}
We have an array containing 11 numbers, The logic is to create a map using these no. in which KEYS of map would be the actual number that must be entered by user and no. of occournce of that actual no. would be the value of that KEY. Here, containsKey() method checks whether the map contain that key already and return boolean value true or false as applied.If it does not contain then add that key into the map and its corresponding value should be 1 otherwise key would have already be contained in map so get the value of that key using get() and increment it by 1. Finally printing the map.
OUTPUT:--
Number 2 Occours 2 time,
Number 4 Occours 3 time,
Number 5 Occours 1 time,
Number 6 Occours 2 time,
Number 7 Occours 1 time,
Number 8 Occours 2 time,