Reputation: 25
Question: Candidates can attempt an entrance exam as many times as they wish. The average score of all attempts is considered in the end. Given a list of scores. find the candidate with the highest score [ average score].
String scores[][] = {{"Ram","155"},
{"Shyam","145"},
{"Ram","156"},
{"Balram","159"},
{"Balram","150"},
{"Ram","135"},
{"Mira","156"},
{"Mira","152"},
{"Shyam","155"}};
Scores are given in two-dimensional array as above. Need suggestions to solve this in efficient way.
Upvotes: 0
Views: 632
Reputation: 138
Also, by this way, You can do the same via Streams
Api,
import java.util.stream.*;
import java.util.*;
public class Solution {
public static void main (String[] args) {
String scores[][] = {{"Bob","80"},{"Charles","85"},{"Rob","70"},{"Bob","100"},{"Charles","75"}};
Map<Object,Double> collectValues = Arrays.stream(scores).collect(Collectors.groupingBy(a->a[0],Collectors.averagingInt(a->Integer.parseInt(a[1]))));
Map.Entry<Object,Double> MaxMarks = collectValues.entrySet().stream().max((e1,e2)->Double.compare(e1.getValue(), e2.getValue())).get();
System.out.println(MaxMarks.getKey() + " :: " + MaxMarks.getValue());
}
Upvotes: 0
Reputation: 44466
What is the reason for reducing the time and space complexity? I strongly believe the brevity and maintainability are more important than the performance.
Since you tagged java-stream, I can suggest you the following approach.
Map<Object, Double> scoreMap = Arrays.stream(scores)
.collect(
Collectors.groupingBy(i -> i[0],
Collectors.averagingInt(i -> Integer.parseInt(i[1])
)));
String winner = scoreMap.entrySet().stream()
.max(Comparator.comparingDouble(e -> e.getValue()))
.get().getKey().toString();
Thanks to @AndyTurner for the .max(..)
parameter suggestion.
Upvotes: 1
Reputation: 25
public String findmaxAverage(String[][] Grades) {
if ( grades == null ) return "";
Map<String,List<Integer>> map = new HashMap<>();
for( String[] grade : Grades ) {
List<Integer> mapList = map.get(grade[0]);
if ( mapList == null ) mapList = new ArrayList<>();
mapList.add(Integer.valueOf(grade[1]));
map.put(grade[0], mapList);
}
double maxAverage = Double.MIN_VALUE;
String winner = "";
for( String name : map.nameSet()) {
System.out.println(name+": "+map.get(name));
List<Integer> mapList = map.get(name);
double average = getAverage(mapList);
if ( average > maxAverage) {
maxAverage = average;
winner = name;
}
}
return winner; }
Upvotes: 0
Reputation: 18255
To reduce time complexity, you can use specific collections:
public static String findMaxScore(String[][] scores) {
final class Candidate implements Comparable<Candidate> {
private final String name;
private int scoreSum;
private int attempts;
public Candidate(String name) {
this.name = name;
}
public void score(int score) {
scoreSum += score;
attempts++;
}
public double avg() {
return (double)scoreSum / attempts;
}
@Override
public int compareTo(Candidate candidate) {
return Double.compare(candidate.avg(), avg());
}
}
Map<String, Candidate> map = new HashMap<>();
for (String[] data : scores) {
map.putIfAbsent(data[0], new Candidate(data[0]));
map.get(data[0]).score(Integer.parseInt(data[1]));
}
return new TreeSet<>(map.values()).iterator().next().name;
}
Upvotes: 1