Two pairs: If there are two pairs of dice with the same number, the player scores the sum of these dice. If not, the player scores 0. For example, 1, 1, 2, 3, 3 placed on "two pairs" gives 8.
examples:
1,1,2,3,3 results 8
1,1,2,3,4 results 0
1,1,2,2,2 results 6
How can find this efficiently?
I've been using following code to find a single pair
int max_difference = 0;
int val1 = 0 , val2 = 0;
Arrays.sort(dice);
for (int i = 0; i < dice.length - 1; i++) {
int x = dice[i+1] - dice[i];
if(x <= max_difference) {
max_difference = x;
val1 = dice[i];
val2 = dice[i+1];
}
}
pairScore = val1 + val2;
No need to make it that complicated, since you're only searching for the resulting number...
int prev = 0;
int result = 0;
int pairs = 0;
Arrays.sort(dice);
for (int i = 0; i < dice.length; i++)
{
int current = dice[i];
if (current == prev)
{
result += current*2;
pairs++;
prev = 0;
}
else prev = current;
}
if (pairs == 2) return result;
else return 0;
I'd use a frequency map, i.e. the number is the key and the value is a counter (so a Map<Integer, Integer>). However, since it is used for dices you could simplify that using an array with a length equal to the maximum dice value (6 for standard dice). Then check the frequencies for each number and get the number of pairs from it.
Example:
int[] diceFrequency = new int[6];
//assuming d is in the range [1,6]
for( int d : dice ) {
//increment the counter for the dice value
diceFrequency[d-1]++;
}
int numberOfPairs = 0;
int pairSum = 0;
for( int i = 0; i < diceFrequency.length; i++ ) {
//due to integer division you get only the number of pairs,
//i.e. if you have 3x 1 you get 1 pair, for 5x 1 you get 2 pairs
int num = diceFrequency[i] / 2;
//total the number of pairs is just increases
numberOfPairs += num;
//the total value of those pairs is the dice value (i+1)
//multiplied by the number of pairs and 2 (since it's a pair)
pairSum += (i + 1 ) * 2 * num;
}
if( numerOfPairs >= 2 ) {
//you have at least 2 pairs, do whatever is appropriate
}
How about use hashmap as below?
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 1, 2, 3, 3, 4);
Map<Integer, Integer> map = Maps.newHashMap();
int result = 0;
for (int i : list) {
int frequency = (int) MapUtils.getObject(map, i, 0);
if (frequency < 2) {
map.put(i, ++frequency);
}
}
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
if (entry.getValue() > 1) {
result += entry.getKey() * entry.getValue();
}
}
System.out.println(result);
}
public static void main(String[] args) {
List<Integer> list = Lists.newArrayList(1, 1, 2, 3, 3);
Map<Integer, Integer> map = new HashMap<>();
int count= 0;
for (int num : list)
if(map.containsKey(num ))
map.put(num , map.get(num )+1);
else
map.put(num , 1);
for (int num : map.keySet()) {
if (map.get(num ) > 1) {
count= count+ (num * map.get(num ));
}
}
System.out.println(count);
}
I hope, I could understand the problem. So we can use thiscode part.
List<Integer> diceList = new ArrayList<Integer>();
diceList.add(1);
diceList.add(1);
diceList.add(2);
diceList.add(4);
diceList.add(3);
diceList.add(3);
diceList.add(6);
diceList.add(8);
Integer prev = null, score = 0;
boolean flag = false;
for (Integer val : diceList) {
if (prev == null || !prev.equals(val)) {
if (flag) {
score = score + prev;
flag = false;
}
prev = val;
} else if (prev == val) {
score = score + prev;
flag = true;
}
}
System.out.println(score);
Related
for example if
int number = 30530;
it has to return 3`
this is what I tried but it's over my mind, I don't know where I lost it and I also would appreciate it if there is any other way to do it without converting it to String
public static int maharishi(int functionNum){
String num = Integer.toString(functionNum);
int length = num.length();
int count = 0;
int tempCount = 0;
int charLetter = 0;
for(int i = 1; i < length; i++ ){
for(int j = 1; j < length; j++){
if(i==1 && j!=1 ){
if(num.charAt(i) == num.charAt(j)){
tempCount++;
if(tempCount > count){
count = tempCount;
charLetter = i;
}
}
}
}
}
char highestChar = num.charAt(charLetter);
int change = Integer.parseInt(String.valueOf(highestChar));
return change;
}
You can use a Map<Character, Integer>:
public static int maharishiMaheshYogi(int functionNum){
// Convert the number to a string
String num = Integer.toString(functionNum);
// Create a Map where you will store each character count
final Map<Character, Integer> counts = new HashMap<>();
// Iterate over each character of this string
final int length = num.length();
for (int i = 0; i < length; i++) {
final char c = num.charAt(i);
// Increment the value of its respective character in the map
final int currentCount = counts.getOrDefault(c, 0);
counts.put(c, currentCount + 1);
}
// Return the key with the maximum value in the map
Map.Entry<Character, Integer> maxEntry = null;
for (Map.Entry<Character, Integer> entry : counts.entrySet()) {
if (maxEntry == null || entry.getValue() > maxEntry.getValue()) {
maxEntry = entry;
}
}
return Integer.parseInt(maxEntry.getKey().toString());
}
Your middle if condition make all fails, you count only when i is 0, so you don't look to other values,
also make the comparison if after the inner loop, don't need to check for every value
the inner loop should start at i+1 to read only next chars
tempCount should be re-initialized at 0 at every round of outer loop
public static int maharishi(int functionNum) {
String num = Integer.toString(functionNum);
int length = num.length();
int count = 0, bestPosition = 0, tempCount;
for (int i = 0; i < length; i++) {
char c = num.charAt(i);
tempCount = 0;
for (int j = i + 1; j < length; j++) {
if (c == num.charAt(j)) {
tempCount++;
}
}
if (tempCount > count) {
count = tempCount;
bestPosition = i;
}
}
char highestChar = num.charAt(bestPosition);
return Integer.parseInt(String.valueOf(highestChar));
}
// testing
System.out.println(maharishi(1234)); // 1
System.out.println(maharishi(12344)); // 4
System.out.println(maharishi(12343)); // 3
System.out.println(maharishi(12342)); // 2
For Stream lovers
public static int maharishi(int functionNum) {
String l = Arrays.stream(Integer.toString(functionNum).split(""))
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.max(Map.Entry.comparingByValue())
.orElseThrow()
.getKey();
return Integer.parseInt(l);
}
If you don't want to convert to string, the easiest way would be to use a "helper array" to hold the count for every possible digit from 0 to 9.
public static int maharishi(int functionNum) {
int [] counts = new int[10];
//count all the digits in the number:
while (functionNum > 0) {
counts[functionNum % 10] += 1;
functionNum /= 10;
}
int record = -1;
int mostRepeated = -1;
//find higest most repeated digit
for (int i = 0; i < counts.length; i++) {
if (counts[i] >= record) {
record = counts[i]; //how many times this digit is in the number
mostRepeated = i; //what digit it is
}
return mostRepeated;
}
What it does is:
Count each digit in the number. Separates digits by division an modulus (remainder).
To separate a digit from a number without converting to string, just get a remainder of division by 10.
Run over the counts from 0 to 9, and store which count is biggest. Return the digit (index) that count belongs to, that is your answer.
You can do this without the array, but you would need more loops.
The principle of separating digits by modulus and division remains the same.
This is my first attempt to use HashMap. Given is a table with n integers. Goal is to calculate in how many common subtables the sum of the numbers is x. I've been trying trying the following. Sample output is 2,10,4. I'm getting 2,10,2. Any idea where I go wrong? Thanks in advance.
public class FindSum {
long count(int[] t, int x) {
HashMap<Integer, Integer> totals = new HashMap<>();
long count = 0;
int sum = 0;
for (int i = 0; i < t.length; i++) {
int value = t[i];
sum += value;
if (totals.containsKey(sum - x)) {
count += totals.get(sum - x);
}
if (value == x) {
count++;
}
totals.put(sum, totals.getOrDefault(sum, 0) + 1);
}
return count;
}
}
Sample output:
FindSum f = new FindSum();
System.out.println(s.count(new int[] {1,3,2,4}, 4)); // 2
System.out.println(s.count(new int[] {0,0,0,0}, 0)); // 10
System.out.println(s.count(new int[] {1,-1,1,-1}, 0)); // 4
I am trying to count the numbers of pairs in an array such that each pair gives the sum of an integer!
I used the following code :
public static int SumPairs(Integer []input, int k){
Map<Integer, Integer> pairs = new HashMap<Integer, Integer>();
int tmp=0;
//System.out.println(pairs.toString());
for(int i=0;i<input.length;i++){
if(pairs.containsKey(input[i])){
System.out.println(pairs.containsKey(input[i]));
System.out.println(input[i] +", "+ pairs.get(input[i]));
input[i]=0;
tmp++;
}
else
pairs.put(k-input[i], input[i]);
}return tmp;
}
the problem is ; for example when my array is 1 2 2 2 3 4 4 4
and sum = 5
it compute as following
(4,1)
(4,1)
(4,1)
(3,2)
I want to prevent the method from using a number more than once !!
so the output will be
(4,1)
(3,2)
I hope this can help
def numberOfPairs(a, k):
# Let's do a o(n) approach by maintaining all the compliments of the K in a
# visited set
compliments = set()
result = set()
for v in a:
# See if the element is in the compliments set, if so thats the pair
if v in compliments:
result.add((v, k-v))
# If the element is not found in visited save the compliment of it in the visited set
else:
compliments.add(k-v)
return len(result)
I use a map storing values and their frequencies:
public static int SumPairs(Integer[] input, int k){
Map<Integer, Integer> frequencies = new HashMap<>();
int pairsCount = 0;
for(int i=0; i<input.length; i++){
int value = input[i];
int complement = k - input[i];
if(frequencies.containsKey(complement)){
int freq = frequencies.get(complement) - 1;
pairsCount++;
//System.out.println(value + ", " + complement);
if(freq == 0){
frequencies.remove(complement);
}else{
frequencies.put(complement, freq);
}
}else{
if(frequencies.containsKey(value)){
frequencies.put(value, frequencies.get(value) + 1);
}else{
frequencies.put(value, 1);
}
}
}
return pairsCount;
}
This works for all the test cases I could think of. Please add in the comment section any test case that this code fails so that I can fix it. If it works, please accept the solution.
public class DistinctPairs {
private static int count(int target, int... arr) {
int count = 0;
Set<String> seen = new HashSet<>();
Set<Integer> set = new HashSet<>();
for (int i = 0; i < arr.length; i++) {
int k = target - arr[i];
int[] pair = new int[]{k, arr[i]};
Arrays.sort(pair);
String s = Arrays.toString(pair);
if (set.contains(k) && !seen.contains(s)) {
count++;
seen.add(s);
// uncomment this print statement to print the distinct pairs
// System.out.println(s);
} else {
set.add(arr[i]);
}
}
return count;
}
// test suite and driver method
public static void main(String[] args) {
System.out.println(count(10, 1, 2, 3, 6, 7, 8, 9, 1) == 3);
System.out.println(count(47, 6, 1, 3, 46, 1, 3, 9) == 1);
System.out.println(count(9, 3, 2, 1, 45, 27, 6, 78, 9, 0) == 2);
System.out.println(count(9, 3, 3, 2, 1, 45, 27, 6, 78, 9, 0) == 2);
System.out.println(count(6, 1, 5, 7, -1) == 2);
System.out.println(count(6, 1, 5, 7, -1, 5) == 2);
System.out.println(count(2, 1, 1, 1, 1) == 1);
System.out.println(count(5, 1, 2, 2, 2, 3, 4, 4, 4) == 2);
System.out.println(count(8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4) == 1);
System.out.println(count(7, 1, 5, 66, 2, 3, 4, 7, 0, 2, 5) == 3);
System.out.println(count(5) == 0);
System.out.println(count(5, 1) == 0);
System.out.println(count(7, 3, 4) == 1);
}
}
Another approach can be to follow the classic solution of Two Sum Problem and add the pairs in a set as you find them, all this in the same pass. This set will be of a custom wrapper class with arr[i] and (target - arr[i]) as it's members and you'll need to override hashcode() and equals() methods in such a way that (a,b) is the same as (b,a). At the end simply return the size of the set. This approach will have the same time and space complexity in Big-O terms as the first approach.
int count(int target, int... nums) {
Set<Pair> uniPairs = new HashSet<>();
Set<Integer> seen = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
int diff = target - nums[i];
if (seen.contains(diff)) {
Pair pair = new Pair(nums[i], diff);
uniPairs.add(pair);
}
seen.add(nums[i]);
}
return uniPairs.size();
}
class Pair {
int a;
int b;
public Pair (int a, int b) {
this.a = a;
this.b = b;
}
#Override
public boolean equals(Object obj) {
Pair pair2 = (Pair) obj;
return ((a == pair2.a) && (b == pair2.b)) || ((b == pair2.a) && (a == pair2.b));
}
#Override
public int hashCode() {
return Objects.hash(a, b) + Objects.hash(b, a);
}
}
public static int sumPairs(Integer[] input, int sum){
List<Integer> complementaries = new ArrayList<>(input.length);
int pairs = 0;
for(Integer number : input){
if(complementaries.contains(number)){
complementaries.remove(number);
pairs++;
}
else{
complementaries.add(sum-number);
}
}
return pairs;
}
Now it should work perfectly.
The complementaries array is used just for keeping track of the numbers needed for making the sum. If it contains the number it means that we iterated over its complementary before, so we can just add one pair and remove the number from the list of complementaries. Oherwise we add the complementary of the current number to the list without incresing the pairs counter.
The code takes an array and returns all possible pairs that have sum as specified. As the question asks to print number of pairs and not the pairs, the length of array divided by 2 would give the desired answer.
int notInArray(float a[],float m,int n)
{
int i,j,k;
for(i=0;i<n;i++)
{
if(a[i] == m)
return 0;
}
return 1;
}
int main() {
int i,j,k;
int n;
scanf("%d",&n); //Input the number of elements in array.
float arr[n];
for(i=0;i<n;i++)
scanf("%f",&arr[i]); //input the array elements
float copyArr = arr[0];
float m;
if (n == 0)
return 0;
scanf("%f",&m); //input the sum
float resArr[n];
int b;
int a=b=0;
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(arr[i]+arr[j]==m && notInArray(resArr,arr[i],n))
{
resArr[a++] = arr[i];
resArr[a++] = arr[j];
//printf("%.0f %.0f\n",arr[i],arr[j]);
}
}
}
printf("All possible pairs: \n");
for(i = 0;i<a;i+=2)
printf("%.0f %.0f\n",resArr[i],resArr[i+1]);
int len = (int)( sizeof(resArr) / sizeof(resArr[0]) )
printf("Number of such pairs: %d",len);
return 0;
}
public void distinctPairs(int[] arr, int k){
int length = arr.length;
int count = 0;
Map<Integer,Integer> pairs = new HashMap<Integer,Integer>();
for(int i=0;i<length;i++){
for(int j=i+1;j<length;j++){
if(arr[i]+arr[j] == k ){
if(!(pairs.containsKey(arr[j])&&pairs.containsValue(arr[i])))
pairs.put(arr[i], arr[j]);
}
}
}
count = pairs.size();
System.out.println("Pairs are "+pairs+" count = "+count);
}
This works for me. Steps I followed.
Check if sum of a pair is equal to required(k).
Check if the pair doesn't already exist in the map.
We can use the hashmap to store all values of the array. Then iterate over the array and check if the map contains (K - a[i] ). If the map contains then increment count and remove both keys from the map.
private int getDistinctPair(int k,int[] input){
HashMap<Integer,Integer> map = new HashMap<>();
int pairs = 0;
for (int i = 0; i < input.length-1; i++) {
map.put(input[i], input[i]);
}
for (int i = 0; i <input.length-1 ; i++) {
int diff = k - input[i];
if(map.containsKey(diff)){
pairs++;
map.remove(diff);
map.remove(input[i]);
}
}
return pairs;
}
You can slove by using below code:
def countPairs(arr, k):
possible_maps = []
for num in arr:
pair_matches = list(filter(lambda n: n + num == k, arr))
if len(pair_matches) > 0:
possible_maps += list(map(lambda nm: (num, nm), pair_matches))
return len(set(map(lambda pair: ','.join(str(n) for n in sorted(pair)), possible_maps)))
Hope this may help you.
My C# way to do this in a single loop with just another list to store temporary diff values.
private static int SumPairs(int[] arr, int sum)
{
Dictionary<int, int> frequency = new Dictionary<int, int>();
List<int> temp = new List<int>();
int count = 0;
foreach (int i in arr)
{
int diff = sum - i;
if (!frequency.ContainsKey(i))
{
if (temp.Contains(i))
{
frequency.Add(i, diff);
count++;
}
else
{
temp.Add(diff);
}
}
};
return count;
}
my C# implementation using Tuple
static List<Tuple<int,int>> GetUniquePairs(int[] arr, int sum)
{
Dictionary<Tuple<int, int>, int> kvp = new Dictionary<Tuple<int, int>, int>();
List<Tuple<int,int>> result = new List<Tuple<int,int>>();
int length = arr.Length;
for(int i = 0;i < length; i++)
{
int j = i + 1;
while (j < length)
{
if(arr[i]+arr[j] == sum)
{
Tuple<int, int> key = new Tuple<int, int>(arr[i], arr[j]);
if (!kvp.ContainsKey(key))
kvp.Add(key, 1);
}
j++;
}
}
var keys = kvp.Keys;
foreach(var k in keys)
{
result.Add(k);
}
return result;
}
The Simplest Solution of your problem of finding distinct pair:
public static int SumPairs(int[] input, int k) {
Map<Integer, Integer> pairs = new HashMap<Integer, Integer>();
int tmp = 0;
for (int data : input) {
if (pairs.containsKey(k - data) && pairs.get(k - data) == 0) {
tmp++;
pairs.put((k - data), pairs.get(k - data) + 1);
} else if (!pairs.containsKey(data)) {
pairs.put(data, 0);
}
}
return tmp;
}
It has been tested for 1 2 2 2 3 4 4 4 and sum = 5. Also for 4 4 4 4 4 4 4 4 4 4 4 4 4 4 and sum = 8.
If any confusion feel free to ask me. Cheers.
import java.util.HashSet;
public class DistinctPairs {
static int numberOfPairs(int[] arr,int k)
{
HashSet<String> s=new HashSet<String>();
int n=arr.length;
int sum=0;
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
sum=arr[i]+arr[j];
if(i==j)
{
continue;
}
else
{
if(sum==k)
{
String l=String.valueOf("("+arr[i]+","+arr[j]+")");
StringBuilder sb=new StringBuilder(l);
String rl=sb.reverse().toString();
if(s.add(l)==false)
{
}
}
}
}
}
System.out.println(s.toString());
return s.size()/2;
}
public static void main(String args[])
{
int b[]={1,5,66,2,3,4,7,0,2,5};
int size=numberOfPairs(b,5);
System.out.println(size);
}
}
I have an input list of words. You check the suffix of the first word to the prefix of the next word.
Eg.
serene
next
tango
extra
{serene,next}= 2common letters {serene,tango}=0 {serene,extra}= 1
{next,serene}= 0 {next,tango}= 1 {next,extra}= 3
{tango,serene}=0 {tango,next}= 0 {tango,extra}= 0
{extra,serene}=0 {extra,next}=0 {extra,tango}=0
You can also switch the order of the words i.e.(next, serene) if overlap letter score is better this way
so you check the overlap scores with each word and finally return the list of words with maximal score
Going by the input list the score is 1
serene,next,tango,extra = 1
Maximal Score is = 5 and the output list returned would be the following:
serine,next,extra,tango
serene,next= 2common letters serene,tango=0 serene,extra= 1
next,serene= 0 next,tango= 1 next,extra= 3
tango,serene=0 tango,next= 0 tango,extra= 0
extra,serene=0 extra,next=0 extra,tango=0
What is the best way to calculate overlap score and return maximal score list in terms of complexity?
I am only able to calculate the overlap score for consecutive words, but that doesn't give maximal score.
You can add all the letters in a list and then do retainAll like:
String one="next", two="extra";
List<Character> oneList=new ArrayList<Character>();
for(Character c : one.toCharArray()) {
oneList.add(c);
}
List<Character> twoList=new ArrayList<Character>();
for(Character c : two.toCharArray()) {
twoList.add(c);
}
List<Character> finalList = new ArrayList<Character>(oneList);
finalList.retainAll(twoList);
System.out.print("There are "+finalList.size()+ " letters in common and they are : ");
for(Character c: finalList){
System.out.print(c+" ");
}
Unfortunately I don't know a better way to convert primitive data type into list other that using Google Guava library or other 3 party API's. If you want to optimize the code then looking them.
I am not sure it is the most efficient approach, but I would compute the matrix of scores for any two consecutive words, and then simply use backtrack to find the longest possible chain.
Backtracking has a poor efficiency reputation, but in current use case, I think it can be used, because we can stop analyze as soon as 2 words have a score of 0. So I can find the correct maximal score 5 and the best sequence in 11 operations.
Code :
public class Overlap {
int[][] matrix;
int total;
int [] bestSeq;
String[] strings;
/**
* #param args the command line arguments
*/
public static void main(String[] strings) {
// TODO code application logic here
Overlap overlap = new Overlap(strings);
int score = overlap.compute();
System.out.println("Best score : " + score);
for (int i : overlap.bestSeq) {
System.out.print(" " + strings[i]);
}
System.out.println(" in " + overlap.total + " operations");
}
public Overlap(String[] strings) {
this.strings = strings;
matrix = matrix(strings);
bestSeq = new int[strings.length];
}
int compute() {
total = 0;
int[] sequence = new int[strings.length];
for (int i=0; i < strings.length; i++) {
sequence[i] = i;
}
return this.bestSequence(-1, sequence, bestSeq);
}
static int findOverlap(String a, String b) {
int la = a.length();
int l = Math.min(la, b.length());
while (l > 0) {
if (a.substring(la - l).equals(b.substring(0, l))) {
return l;
}
l--;
}
return 0;
}
static int[][] matrix(String[] strings) {
int l = strings.length;
int[][] mx = new int[l][l];
for (int i = 0; i < l - 1; i++) {
for (int j = i + 1; j < l; j++) {
mx[i][j] = findOverlap(strings[i], strings[j]);
}
}
return mx;
}
int bestSequence(int initial, int[] sequence, int[] best) {
total += 1;
int max = 0;
if (best.length != sequence.length) {
throw new java.lang.IllegalArgumentException();
}
int l = sequence.length;
int[] newseq = new int[l - 1];
int[] newbest = new int[l - 1];
for (int i : sequence) {
int val = (initial == -1) ? 0 : matrix[initial][i];
if ((val > 0) || (initial == -1)) {
int k = 0;
for (int j : sequence) {
if (j != i) {
newseq[k++] = j;
}
}
val += bestSequence(i, newseq, newbest);
if (val > max) {
max = val;
best[0] = i;
System.arraycopy(newbest, 0, best, 1, l - 1);
}
}
}
if (max == 0) {
System.arraycopy(sequence, 0, best, 0, l);
}
return max;
}
}
With the arguments serene next tango extra, it prints :
Best score : 5
serene next extra tango
in 11 operations
Are there any functions (as part of a math library) which will calculate mean, median, mode and range from a set of numbers.
Yes, there does seem to be 3rd libraries (none in Java Math). Two that have come up are:
http://opsresearch.com/app/
http://www.iro.umontreal.ca/~simardr/ssj/indexe.html
but, it is actually not that difficult to write your own methods to calculate mean, median, mode and range.
MEAN
public static double mean(double[] m) {
double sum = 0;
for (int i = 0; i < m.length; i++) {
sum += m[i];
}
return sum / m.length;
}
MEDIAN
// the array double[] m MUST BE SORTED
public static double median(double[] m) {
int middle = m.length/2;
if (m.length%2 == 1) {
return m[middle];
} else {
return (m[middle-1] + m[middle]) / 2.0;
}
}
MODE
public static int mode(int a[]) {
int maxValue, maxCount;
for (int i = 0; i < a.length; ++i) {
int count = 0;
for (int j = 0; j < a.length; ++j) {
if (a[j] == a[i]) ++count;
}
if (count > maxCount) {
maxCount = count;
maxValue = a[i];
}
}
return maxValue;
}
UPDATE
As has been pointed out by Neelesh Salpe, the above does not cater for multi-modal collections. We can fix this quite easily:
public static List<Integer> mode(final int[] numbers) {
final List<Integer> modes = new ArrayList<Integer>();
final Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
int max = -1;
for (final int n : numbers) {
int count = 0;
if (countMap.containsKey(n)) {
count = countMap.get(n) + 1;
} else {
count = 1;
}
countMap.put(n, count);
if (count > max) {
max = count;
}
}
for (final Map.Entry<Integer, Integer> tuple : countMap.entrySet()) {
if (tuple.getValue() == max) {
modes.add(tuple.getKey());
}
}
return modes;
}
ADDITION
If you are using Java 8 or higher, you can also determine the modes like this:
public static List<Integer> getModes(final List<Integer> numbers) {
final Map<Integer, Long> countFrequencies = numbers.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
final long maxFrequency = countFrequencies.values().stream()
.mapToLong(count -> count)
.max().orElse(-1);
return countFrequencies.entrySet().stream()
.filter(tuple -> tuple.getValue() == maxFrequency)
.map(Map.Entry::getKey)
.collect(Collectors.toList());
}
Check out commons math from apache. There is quite a lot there.
public static Set<Double> getMode(double[] data) {
if (data.length == 0) {
return new TreeSet<>();
}
TreeMap<Double, Integer> map = new TreeMap<>(); //Map Keys are array values and Map Values are how many times each key appears in the array
for (int index = 0; index != data.length; ++index) {
double value = data[index];
if (!map.containsKey(value)) {
map.put(value, 1); //first time, put one
}
else {
map.put(value, map.get(value) + 1); //seen it again increment count
}
}
Set<Double> modes = new TreeSet<>(); //result set of modes, min to max sorted
int maxCount = 1;
Iterator<Integer> modeApperance = map.values().iterator();
while (modeApperance.hasNext()) {
maxCount = Math.max(maxCount, modeApperance.next()); //go through all the value counts
}
for (double key : map.keySet()) {
if (map.get(key) == maxCount) { //if this key's value is max
modes.add(key); //get it
}
}
return modes;
}
//std dev function for good measure
public static double getStandardDeviation(double[] data) {
final double mean = getMean(data);
double sum = 0;
for (int index = 0; index != data.length; ++index) {
sum += Math.pow(Math.abs(mean - data[index]), 2);
}
return Math.sqrt(sum / data.length);
}
public static double getMean(double[] data) {
if (data.length == 0) {
return 0;
}
double sum = 0.0;
for (int index = 0; index != data.length; ++index) {
sum += data[index];
}
return sum / data.length;
}
//by creating a copy array and sorting it, this function can take any data.
public static double getMedian(double[] data) {
double[] copy = Arrays.copyOf(data, data.length);
Arrays.sort(copy);
return (copy.length % 2 != 0) ? copy[copy.length / 2] : (copy[copy.length / 2] + copy[(copy.length / 2) - 1]) / 2;
}
If you only care about unimodal distributions, consider sth. like this.
public static Optional<Integer> mode(Stream<Integer> stream) {
Map<Integer, Long> frequencies = stream
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
return frequencies.entrySet().stream()
.max(Comparator.comparingLong(Map.Entry::getValue))
.map(Map.Entry::getKey);
}
public class Mode {
public static void main(String[] args) {
int[] unsortedArr = new int[] { 3, 1, 5, 2, 4, 1, 3, 4, 3, 2, 1, 3, 4, 1 ,-1,-1,-1,-1,-1};
Map<Integer, Integer> countMap = new HashMap<Integer, Integer>();
for (int i = 0; i < unsortedArr.length; i++) {
Integer value = countMap.get(unsortedArr[i]);
if (value == null) {
countMap.put(unsortedArr[i], 0);
} else {
int intval = value.intValue();
intval++;
countMap.put(unsortedArr[i], intval);
}
}
System.out.println(countMap.toString());
int max = getMaxFreq(countMap.values());
List<Integer> modes = new ArrayList<Integer>();
for (Entry<Integer, Integer> entry : countMap.entrySet()) {
int value = entry.getValue();
if (value == max)
modes.add(entry.getKey());
}
System.out.println(modes);
}
public static int getMaxFreq(Collection<Integer> valueSet) {
int max = 0;
boolean setFirstTime = false;
for (Iterator iterator = valueSet.iterator(); iterator.hasNext();) {
Integer integer = (Integer) iterator.next();
if (!setFirstTime) {
max = integer;
setFirstTime = true;
}
if (max < integer) {
max = integer;
}
}
return max;
}
}
Test data
Modes {1,3} for { 3, 1, 5, 2, 4, 1, 3, 4, 3, 2, 1, 3, 4, 1 };
Modes {-1} for { 3, 1, 5, 2, 4, 1, 3, 4, 3, 2, 1, 3, 4, 1 ,-1,-1,-1,-1,-1};
As already pointed out by Nico Huysamen, finding multiple mode in Java 1.8 can be done alternatively as below.
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
public static void mode(List<Integer> numArr) {
Map<Integer, Integer> freq = new HashMap<Integer, Integer>();;
Map<Integer, List<Integer>> mode = new HashMap<Integer, List<Integer>>();
int modeFreq = 1; //record the highest frequence
for(int x=0; x<numArr.size(); x++) { //1st for loop to record mode
Integer curr = numArr.get(x); //O(1)
freq.merge(curr, 1, (a, b) -> a + b); //increment the frequency for existing element, O(1)
int currFreq = freq.get(curr); //get frequency for current element, O(1)
//lazy instantiate a list if no existing list, then
//record mapping of frequency to element (frequency, element), overall O(1)
mode.computeIfAbsent(currFreq, k -> new ArrayList<>()).add(curr);
if(modeFreq < currFreq) modeFreq = currFreq; //update highest frequency
}
mode.get(modeFreq).forEach(x -> System.out.println("Mode = " + x)); //pretty print the result //another for loop to return result
}
Happy coding!
Here's the complete clean and optimised code in JAVA 8
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) {
/*Take input from user*/
Scanner sc = new Scanner(System.in);
int n =0;
n = sc.nextInt();
int arr[] = new int[n];
//////////////mean code starts here//////////////////
int sum = 0;
for(int i=0;i<n; i++)
{
arr[i] = sc.nextInt();
sum += arr[i];
}
System.out.println((double)sum/n);
//////////////mean code ends here//////////////////
//////////////median code starts here//////////////////
Arrays.sort(arr);
int val = arr.length/2;
System.out.println((arr[val]+arr[val-1])/2.0);
//////////////median code ends here//////////////////
//////////////mode code starts here//////////////////
int maxValue=0;
int maxCount=0;
for(int i=0; i<n; ++i)
{
int count=0;
for(int j=0; j<n; ++j)
{
if(arr[j] == arr[i])
{
++count;
}
if(count > maxCount)
{
maxCount = count;
maxValue = arr[i];
}
}
}
System.out.println(maxValue);
//////////////mode code ends here//////////////////
}
}