Given an array of integers, which can contain both +ve and -ve numbers. I've to maximize the product of any 3 elements of the array. The elements can be non-contiguous.
Some examples:
int[] arr = {-5, -7, 4, 2, 1, 9}; // Max Product of 3 numbers = -5 * -7 * 9
int[] arr2 = {4, 5, -19, 3}; // Max Product of 3 numbers = 4 * 5 * 3
I've tried solving it using Dynamic Programming, but I'm not getting the expected result. It is returning the result often involving the same number twice in the multiplication. So, for the array - {4, 2, 1, 9}, it is returning - 32, which is 4 * 4 * 2.
Here's my code:
public static int maxProduct(int[] arr, int count) {
return maxProduct(arr, 0, arr.length - 1, count);
}
private static int maxProduct(int[] arr, int fromIndex, int toIndex, int count) {
if (count == 1) {
return maximum(arr, fromIndex, toIndex);
} else if (toIndex - fromIndex + 1 < count) {
return 1;
} else {
return MathUtil.max(maxProduct(arr, fromIndex, toIndex - 1, count - 1) * arr[toIndex - 1],
maxProduct(arr, fromIndex, toIndex - 1, count));
}
}
MathUtil.max(int a, int b) is a method that gives maximum of a and b.
The two values I pass to max method there are:
maxProduct, when we consider last element as a part of product.
maxProduct, when we don't consider it as a part of product.
count contains the number of element we want to consider. Here 3.
For count == 1, we have to find maximum of 1 element from array. That means, we have to use maximum array element.
If toIndex - fromIndex + 1 < count, means, there are not enough elements in the array between those indices.
I've an intuition that, the first if condition is one of the reason of failure. Because, it is only considering maximum element from an array, while the maximum product may comprise of negative numbers too. But I don't know how to take care of that.
The reason I'm using Dynamic Programming is that I can then generalize this solution to work for any value of count. Of course, if someone have any better approach, even for count = 3, I welcome the suggestion (I would want to avoid sorting the array, as that will be another O(nlogn) at the least).
Sort the given array in ascending order and you have to take the maximum of these cases
to get the answer..
product of last 3 numbers in sorted array
Product of first two and last number in the sorted array
For count=3, your solution will have 1 of 3 forms:
The 3 largest positive values (assuming there ARE 3 positive values)
The largest positive value and the 2 smallest negative values (assuming there IS a positive value)
The 3 least negative values
Each of which can be solved a lot easier than using DP.
It is always max of(smallest two negative digits and biggest positive or
last three big positive numbers)
public static void main(String args[]){
int array[] = {-5,-1,4,2,1,9};
Arrays.sort(array);
int length = array.length;
System.out.println(max(array[0]*array[1]*array[length-1],
array[length-1]*array[length-2]*array[length-3]));
}
Sort The Array
Then max will be either the product of last 3 or first 2(if negative) and the last.
Arrays.sort(arr);
int max1 = (arr[n - 1] * arr[n - 2] * arr[n - 3]);
int max2 = (arr[0] * arr[1] * arr[n - 1]);
System.out.println(max1 > max2 ? max1 : max2);
n=len(arr1)
for i in range(0,n):
arr1[i]=abs(arr1[i])
arr1.sort()
return arr1[n-1]*arr1[n-2]*arr1[n-3]
even though this solution is simple this basically involves sorting the array and then taking the product of last three numbers , before that is to be done ; all the values in the array should be positive .which is done by the first for loop.
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ComputeMaxProduct {
public static void main(String[] args){
int [] arr = {4, 5, -19, 3};
List<Integer> superSet = new ArrayList<>();
for (int a : arr ){
superSet.add(a);
}
int k = 3;
int maxProduct = computeMaxProduct(superSet, k);
System.out.println("maximum product is : " + maxProduct);
}
private static int computeMaxProduct( List<Integer> superSet, int k ){
List<Set<Integer>> res = getSubsets(superSet,k);
int maxProduct = 1;
for(int index = 0; index < res.size(); index++){
int product = 1;
for(Integer i : res.get(index)){
product *= i;
}
if (product > maxProduct){
maxProduct = product;
}
}
return maxProduct;
}
private static void getSubsets(List<Integer> superSet, int k, int idx, Set<Integer> current,List<Set<Integer>> solution) {
//successful stop clause
if (current.size() == k) {
solution.add(new HashSet<>(current));
return;
}
//unseccessful stop clause
if (idx == superSet.size()) return;
Integer x = superSet.get(idx);
current.add(x);
//"guess" x is in the subset
getSubsets(superSet, k, idx+1, current, solution);
current.remove(x);
//"guess" x is not in the subset
getSubsets(superSet, k, idx+1, current, solution);
}
public static List<Set<Integer>> getSubsets(List<Integer> superSet, int k) {
List<Set<Integer>> res = new ArrayList<>();
getSubsets(superSet, k, 0, new HashSet<Integer>(), res);
return res;
}
}
public class MaxProdofThreenumbers {
public int ThreeLargeNumbers(int[] a) {
int topfirstpos = 0;
int topsecpos = 0;
int topthirdpos = 0;
int topfirstneg = 0;
int topsecneg = 0;
int prodneg = 0;
int prodpos = 0;
int prodmax = 0;
boolean flag = false;
for (int i = 0; i < a.length; i++) {
String num = a[i] + "";
if (num.contains("-")) {
String array[] = num.split("-");
num = array[1];
flag = true;
} else
flag = false;
if (flag) {
if (topfirstneg < Integer.valueOf(num)) {
topsecneg = topfirstneg;
topfirstneg = Integer.valueOf(num);
} else if (topsecneg < Integer.valueOf(num)) {
topsecneg = Integer.valueOf(num);
}
}
else {
if (topfirstpos < Integer.valueOf(num)) {
topsecpos = topfirstpos;
topfirstpos = Integer.valueOf(num);
}
else if (topsecpos < Integer.valueOf(num)) {
topthirdpos = topsecpos;
topsecpos = Integer.valueOf(num);
}
else if (topthirdpos < Integer.valueOf(num)) {
topthirdpos = Integer.valueOf(num);
}
}
}
prodneg = topfirstneg * topsecneg;
prodpos = topfirstpos * topsecpos;
if (prodneg > prodpos) {
prodmax = prodneg * topfirstpos;
} else {
prodmax = prodpos * topthirdpos;
}
return prodmax;
}
public static void main(String a[]) {
int list[] = { -29, 3, -2, -57, 8, -789, 34 };
MaxProdofThreenumbers t = new MaxProdofThreenumbers();
System.out.println(t.ThreeLargeNumbers(list));
}
}
This problem can be done in O(n) time.
Keep track of these 5 variables and update them during every iteration:
highest product of 3 numbers
highest product of 2 numbers
highest element
lowest product of 2 numbers
lowest element
After last iteration, product of 3 numbers variable will be the answer.
package interviewProblems;
import interviewProblems.exceptions.ArrayTooSmallException;
import java.util.PriorityQueue;
public class Problem5 {
public static void main(String[] args) {
int[] data1 = new int[]{}; // error
int[] data2 = new int[]{1, 5}; // error
int[] data3 = new int[]{1, 4, 2, 8, 9}; // Case: all positive --> 3-max
int[] data4 = new int[]{10, 11, 12, -20}; // Case: 1 negative --> 3-max
int[] data5 = new int[]{-5, -6, -10, 7, 8, 9}; // Case: 2+ negative --> 3-max || 1-max 2-small
int[] data6 = new int[]{-12, -10, -6, -4}; // Case: all negative --> 3-max
int[] data7 = new int[]{-10, -10, 1, 3, 2};
try {
productOfThree(data2);
} catch (Exception e) {
System.out.println(e.getMessage());
}
try {
System.out.println(productOfThree(data3));
System.out.println(productOfThree(data4));
System.out.println(productOfThree(data5));
System.out.println(productOfThree(data6));
System.out.println(productOfThree(data7));
} catch (Exception e) {
System.out.println("You should not see this line");
}
}
// O(n) time
// O(1) memory
private static int productOfThree(int[] data) throws ArrayTooSmallException {
if (data.length < 3) {
throw new ArrayTooSmallException(3 , data.length);
}
PriorityQueue<Integer> maxNumbers = new PriorityQueue<>(); // keep track of 3 largest numbers
PriorityQueue<Integer> minNumbers = new PriorityQueue<>((x, y) -> y - x); // keep track of two smallest numbers
for (int i = 0; i < data.length; i++) {
maxNumbers.add(data[i]);
minNumbers.add(data[i]);
if(maxNumbers.size() > 3) {
maxNumbers.poll();
}
if(minNumbers.size() > 2){
minNumbers.poll();
}
}
int maxLow = maxNumbers.poll();
int maxMed = maxNumbers.poll();
int maxHigh = maxNumbers.poll();
int minHigh = minNumbers.poll();
int minLow = minNumbers.poll();
int possibleProduct1 = maxHigh * maxMed * maxLow;
int possibleProduct2 = maxHigh * minHigh * minLow;
return Math.max(possibleProduct1, possibleProduct2);
}
// O(n) time
// O(n) memory
// private static int productOfThree(int[] data) throws ArrayTooSmallException {
// if(data.length < 3) {
// throw new ArrayTooSmallException("Array must be at least 3 long to preform productOfThree(int[] data)");
// }
//
// PriorityQueue<Integer> maxNumbers = new PriorityQueue<>((x , y) -> y - x); // keep track of 3 largest numbers
// PriorityQueue<Integer> minNumbers = new PriorityQueue<>(); // keep track of two smallest numbers
//
// for(int i = 0; i < data.length; i++) {
// maxNumbers.add(data[i]);
// minNumbers.add(data[i]);
// }
//
// int maxHigh = maxNumbers.poll();
// int maxMed = maxNumbers.poll();
// int maxLow = maxNumbers.poll();
//
// int minLow = minNumbers.poll();
// int minHigh = minNumbers.poll();
//
// int possibleProduct1 = maxHigh * maxMed * maxLow;
// int possibleProduct2 = maxHigh * minHigh * minLow;
//
// return Math.max(possibleProduct1 , possibleProduct2);
// }
}
https://github.com/amilner42/interviewPractice/blob/master/src/interviewProblems/Problem5.java
Assuming that the a positive product is bigger than a negative product, I can think of the following way it can be done.
If there are less than two negative elements in the array, then it is simple, product of top 3(top == positive) elements.
If negative numbers are chosen, at least 2 of them have to be in the product, so that product is positive. Therefore whatever be the case, the top (positive) number will always be part of the product.
Multiply last two(negatives) and 2nd and 3rd highest(positives) and compare. Out of these two pairs whichever has higher value, will be part of the final product along with the top positive shortlisted in line above.
https://stackoverflow.com/users/2466168/maandoo 's answer is the best.
As, he said, answer is max(l,r) for
r. product of last 3 numbers in sorted array
l. product of first two and last number in the sorted array
Let me elaborate now.
I think this problem is confusion because each number can be positive, negative and zero. 3 state is annoying to mange by programming, you know!
Case 1) Given three numbers
Use them all
Case 2) Given four numbers
Positive number is show +, Negative number is show -.
Numbers are sorted from left to right.
Case 2-1)
2-1) ---- => r (answer is negative)
2-2) ---+ => l (answer is positive)
2-3) --++ => l (answer is positive)
2-4) -+++ => r (answer is positive)
2-5) ++++ => r (answer is positive)
When a 0 is mixed in four numbers, it comes between
- and +.
Case 2-2)
Suppose smallest + was actually 0.
2-1) ---- => r (answer is negative)
2-2) ---0 => l (answer is 0)
2-3) --0+ => l (answer is positive)
2-4) -0++ => r (answer is 0)
2-5) 0+++ => r (answer is positive)
Case 2-3)
Suppose largest - was actually 0.
2-1) ---0 => r (answer is 0)
2-2) --0+ => l (answer is positive)
2-3) -0++ => l (answer is 0)
2-4) 0+++ => r (answer is positive)
2-5) ++++ => r (answer is positive)
Case 2-4)
If more than two 0 is mixed, products becomes always 0 because
-00+
Summary for Case 2)
answer is consistent among Case 2-1 ~ 2-4.
2-1) r (negative or 0)
2-2) l (0 or positive)
2-3) l (0 or positive)
2-4) r (0 or positive)
2-5) r (positive)
So, we do not need to worry about 0 actually.
Case 3) More than four numbers
The same with Case 2
u have to consider 3 cases:
1. max 3 positive elements can be the first answer(say 10*20*70).
2. max positive elements multiplied by 2 most negative answers is another candidate(say20*-40*-60).
3.in case where all array elements are negative,3 elements with minimum negative magnitude is answer(-1*-2*-3 in [-1,-2,3,-4,-5]).
for simplicity of question we can merge 1st and 3rd case.
find 3 maximum elements of array, similarly find 2 minimum elements of array.
u will get 2 candidates. Print the maximum of those candidates.
C++ Code:
#include <iostream>
#include <limits.h>
using namespace std;
int main()
{
int n; cin>>n; int arr[n]; for(int a=0;a<n;a++) cin>>arr[a];
bool flag=0;
int max1=INT_MIN,max2=INT_MIN,max3=INT_MIN;
int min1=INT_MAX,min2=INT_MAX;
for(int a=0;a<n;a++)
{
if(arr[a]>max1) {max3=max2; max2=max1; max1=arr[a];}
else if(arr[a]>max2) {max3=max2; max2=arr[a];}
else if(arr[a]>max3) max3=arr[a]; flag=1;
if(arr[a]<min1) {min2=min1; min1=arr[a];}
else if(arr[a]<min2) min2=arr[a];
}
int prod1=INT_MIN,prod2=INT_MIN;
if(max1>INT_MIN && max2>INT_MIN && max3>INT_MIN) prod1=max1*max2*max3;
if(max1>INT_MIN && min1<INT_MAX && min2<INT_MAX) prod2=max1*min1*min2;
cout<<max(prod1,prod2)<<endl;
}
// Here is a simple java program to find the maximum product of three numbers in an array.
import java.util.*;
import java.lang.*;
class MOHAN_BERA
{
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
System.out.println("enter the lenth of array:");
int num1=s.nextInt();
int[] num2=new int[num1];
System.out.println("enter the numbers of array:");
for(int i=0;i<num1;i++)
{
num2[i]=s.nextInt();
}
Arrays.sort(num2);//sort the array
long max1=num2[num1-1]*num2[num1-2]*num2[num1-3];//Three last numbers, can be three positive numbers
long max2=num2[num1-1]*num2[0]*num2[1];//last numbers and first two numbers,can be first two negetive and last one positive numbers
long max3=num2[0]*num2[1]*num2[2];//for all negetives numbers
long max=max1;//max1 greatest
if(max<max2 && max3<max2) //max2 greatest
{
max=max2;
}
else if(max<max3 && max2<max3)//max3 greatest
{
max=max3;
}
System.out.println(max);
}
}
in JavaScript
function largestProduct(ints) {
ints.sort((a, b) => b - a);
return ints[0] * ints[1] * ints[2];
}
Language - C#
Greedy Approach
Time Complexity O(n)
public static int GetHighestProductOfThree(int[] arrayOfInts)
{
if (arrayOfInts.Length < 3)
{
throw new ArgumentException("Array should be atleast 3 items", nameof(arrayOfInts));
}
int highest = Math.Max(arrayOfInts[0], arrayOfInts[1]);
int lowest = Math.Min(arrayOfInts[0], arrayOfInts[1]);
int highestProductOf2 = arrayOfInts[0] * arrayOfInts[1];
int lowestProductOf2 = arrayOfInts[0] * arrayOfInts[1];
int highestProductOf3 = arrayOfInts[0] * arrayOfInts[1] * arrayOfInts[2];
for (int i = 2; i < arrayOfInts.Length; i++)
{
int current = arrayOfInts[i];
highestProductOf3 = Math.Max(Math.Max(
highestProductOf3,
current * highestProductOf2),
current * lowestProductOf2);
highestProductOf2 = Math.Max(Math.Max(
highestProductOf2,
current * highest),
current * lowest);
lowestProductOf2 = Math.Min(Math.Min(
lowestProductOf2,
current * highest),
current * lowest);
highest = Math.Max(highest, current);
lowest = Math.Min(lowest, current);
}
return highestProductOf3;
}
Thanks to interviewcake.com
Detailed Explanation of this Algorithm
def solution(A):
if len(A) < 3:
return 0
A.sort()
product = A[len(A)-1] * A[len(A)-2] * A[len(A)-3]
if A[0] < 0 and A[1] < 0:
if A[0] * A[1] * A[len(A)-1] > product:
product = A[0] * A[1] * A[len(A)-1]
return product
Below is my solution in JavaScript:
function solution(A) {
A = A.sort((a, b) => b - a);
var product = A[0] * A[1] * A[2];
var length = A.length;
if (A[0] < 0) return product;
if (A[length - 1] * A[length - 2] * A[0] > product) {
return A[length - 1] * A[length - 2] * A[0];
}
if (A[2] < 0 && length >= 5 && A[3] * A[4] < A[0] * A[1]) {
return A[2] * A[3] * A[4];
}
return product;
}
This Solution is applicable only if there are 3 numbers needed. If It's dynamic or say user can ask for 4 or 5 then this solution is not suitable for it.
Without sorting you can achieve it by find out max 3 numbers from array and multiply 3 numbers, because max product requires max number from array.
public class FindOutProductPair {
public static void main(String args[]) {
int arr[]= {2,4,3,6,12,1};
// int arr1[]= {2,4,3,7,6,5,1};
// int arr1[]= {-1,-4,3,7,6,5,1};
int arr1[]= {3,2};
int max1=1,max2=1,max3=1;
for(int i=0;i<arr1.length;i++) {
if(max1 < arr1[i]) {
max3=max2;
max2=max1;
max1=arr1[i];
}else {
if(max2 < arr1[i]) {
max3=max2;
max2=arr1[i];
}
else {
if(max3< arr1[i]) {
max3=arr1[i];
}
}
}
}
System.out.println((max3+" "+max2+" "+max1)+" <-- "+(max3*max2*max1));
}
}
Could be like this in JAVA:
public final static int maxProizvedenieTrexChisel(Integer m []){
Arrays.sort(m,(g,g1)->g-g1);
System.out.println(Arrays.toString(m));
int mx1=m[0]*m[1]*m[2];
int mx2=m[m.length-1]*m[m.length-2]*m[m.length-3];
int mx3=m[0]*m[1]*m[m.length-1];
if(mx1>mx2&mx1>mx3)
return mx1;
else if(mx2>mx1&mx2>mx3)
return mx2;
return mx3;
}
could be solve using 5 variables with O(n) pass.
Max Product can be formed by either:
1. Max1 * Max2 * Max3
2. Max1 * Min1 * min2
where Max is maximum element and Min stands for minimum.
Here is my Java solution:
int maxProduct(int[] arr) {
int max1, max2, max3 = Integer.MIN_VALUE;
max1 = max3;
max2 = max3;
int min1 = Integer.MAX_VAULE;
int min2 = Integer.MAX_VAULE;
for(int n : arr) {
if (n <= min1) { // n is smaller than all
min2 = min1;
min1 = n;
} else if (n < min2) { // n lies between min1 and min2
min2 = n;
}
if (n >= max1) { // n is greater than all
max3 = max2;
max2 = max1;
max1 = n;
} else if (n >= max2) { // n lies betweeen max1 and max2
max3 = max2;
max2 = n;
} else if (n > max3) { // n lies betwen max2 and max3
max3 = n;
}
}
}
JavaScript code
function solution(A) {
if(A.length<3){
return 0;
}
let maxElement = Number.NEGATIVE_INFINITY;
let idx = null;
for(let i=0;i<A.length;i++){
if(A[i]>maxElement){
maxElement = A[i];
idx = i;
}
}
A.splice(idx,1);
A.sort((a,b)=>b-a);
let n = A.length;
let positiveMax = A[0]*A[1]*maxElement;
let negativeMax = A[n-1]*A[n-2]*maxElement;
return Math.max(positiveMax,negativeMax);
}
You can use inbuilt sort function of Javascript.Need to careful while finding max triplet product as in case of array with -ve numbers product will be combination first 2 and last and in case all +ve last 3 number product will be result.You can refer my jsfiddle. Also complexity of this algorithm is O(nlogn)
var arr=[-10, 3, 5, 6, -20];
function maxTripletProduct(data)
{
var sortedarr=data.sort(function(a,b){
return a-b;
})
console.log(sortedarr);
let length=sortedarr.length;
let product1 = sortedarr[length-3]*sortedarr[length-2]*sortedarr[length-1]
let product2=sortedarr[0]*sortedarr[1]*sortedarr[length-1];
if(product2>product1)
console.log(product2);
else
console.log(product1);
}
maxTripletProduct(arr);
Related
How can I randomly find a combination from an array with duplicate elements and it's sum equal n.
Example
array is [1, 2, 2, 3] and n is 3
answers are 1+2, 1+2, 3
If randomSubsetSum(array, n) is solution, then randomSubsetSum([1,2,2,3], 3) will return one of 1+2, 1+2, 3. Note: 1+2 appear twice as often as 3
A real-world scenario: random selection of questions from a question bank for an exam
I found some similar questions and solutions:
Q: Finding all possible combinations of numbers to reach a given sum
A: solution A and solution B
Q: Rank and unrank integer partition with k parts
A: solution C
Defect
solution A and solution B can not random find combination. solution C does not allow duplicate elements.
My Java solution
public List<Integer> randomSubsetSum(List<Integer> list, Integer n) {
list.removeIf(e -> e > n);
int maxSum = list.stream().reduce(0, Integer::sum);
if (maxSum < n) {
throw new RuntimeException("maxSum of list lower than n!");
}
if (maxSum == n) {
return list;
}
final SecureRandom random = new SecureRandom();
// maybe helpful, not important
final Map<Integer, List<Integer>> map = list.stream().collect(Collectors.groupingBy(Function.identity()));
final List<Integer> keys = new ArrayList<>(map.keySet());
final List<Integer> answers = new ArrayList<>();
int sum = 0;
while (true) {
int keyIndex = random.nextInt(keys.size());
Integer key = keys.get(keyIndex);
sum += key;
// sum equal n
if (sum == n) {
List<Integer> elements = map.get(key);
answers.add(elements.get(random.nextInt(elements.size())));
break;
}
// sum below n
if (sum < n) {
List<Integer> elements = map.get(key);
answers.add(elements.remove(random.nextInt(elements.size())));
if (elements.isEmpty()) {
map.remove(key);
keys.remove(keyIndex);
}
continue;
}
// sum over n: exists (below = n - sum + key) in keys
int below = n - sum + key;
if (CollectionUtils.isNotEmpty(map.get(below))) {
List<Integer> elements = map.get(below);
answers.add(elements.get(random.nextInt(elements.size())));
break;
}
// sum over n: exists (over = sum - n) in answers
int over = sum - n;
int answerIndex =
IntStream.range(0, answers.size())
.filter(index -> answers.get(index) == over)
.findFirst().orElse(-1);
if (answerIndex != -1) {
List<Integer> elements = map.get(key);
answers.set(answerIndex, elements.get(random.nextInt(elements.size())));
break;
}
// Point A. BUG: may occur infinite loop
// sum over n: rollback sum
sum -= key;
// sum over n: remove min element in answer
Integer minIndex =
IntStream.range(0, answers.size())
.boxed()
.min(Comparator.comparing(answers::get))
// never occurred
.orElseThrow(RuntimeException::new);
Integer element = answers.remove((int) minIndex);
sum -= element;
if (keys.contains(element)) {
map.get(element).add(element);
} else {
keys.add(element);
map.put(element, new ArrayList<>(Collections.singleton(element)));
}
}
return answers;
}
At Point A, infinite loop may occur(eg. randomSubsetSum([3,4,8],13)) or use a lot of time. How to fix this bug or is there any other solution?
Here is a solution lightly adapted from solution A.
from random import random
def random_subset_sum(array, target):
sign = 1
array = sorted(array)
if target < 0:
array = reversed(array)
sign = -1
# Checkpoint A
last_index = {0: [[-1,1]]}
for i in range(len(array)):
for s in list(last_index.keys()):
new_s = s + array[i]
total = 0
for index, count in last_index[s]:
total += count
if 0 < (new_s - target) * sign:
pass # Cannot lead to target
elif new_s in last_index:
last_index[new_s].append([i,total])
else:
last_index[new_s] = [[i, total]]
# Checkpoint B
answer_indexes = []
last_choice = len(array)
while -1 < last_choice:
choice = None
total = 0
for i, count in last_index[target]:
if last_choice <= i:
break
total += count
if random() <= count / total:
choice = i
target -= array[choice]
last_choice = choice
if -1 < choice:
answer_indexes.append(choice)
return [array[i] for i in reversed(answer_indexes)]
I have numbers like 1100, 1002, 1022 etc. I would like to have the individual digits, for example for the first number 1100 I want to have 1, 1, 0, 0.
How can I get it in Java?
To do this, you will use the % (mod) operator.
int number; // = some int
while (number > 0) {
print( number % 10);
number = number / 10;
}
The mod operator will give you the remainder of doing int division on a number.
So,
10012 % 10 = 2
Because:
10012 / 10 = 1001, remainder 2
Note: As Paul noted, this will give you the numbers in reverse order. You will need to push them onto a stack and pop them off in reverse order.
Code to print the numbers in the correct order:
int number; // = and int
LinkedList<Integer> stack = new LinkedList<Integer>();
while (number > 0) {
stack.push( number % 10 );
number = number / 10;
}
while (!stack.isEmpty()) {
print(stack.pop());
}
Convert it to String and use String#toCharArray() or String#split().
String number = String.valueOf(someInt);
char[] digits1 = number.toCharArray();
// or:
String[] digits2 = number.split("(?<=.)");
In case you're already on Java 8 and you happen to want to do some aggregate operations on it afterwards, consider using String#chars() to get an IntStream out of it.
IntStream chars = number.chars();
How about this?
public static void printDigits(int num) {
if(num / 10 > 0) {
printDigits(num / 10);
}
System.out.printf("%d ", num % 10);
}
or instead of printing to the console, we can collect it in an array of integers and then print the array:
public static void main(String[] args) {
Integer[] digits = getDigits(12345);
System.out.println(Arrays.toString(digits));
}
public static Integer[] getDigits(int num) {
List<Integer> digits = new ArrayList<Integer>();
collectDigits(num, digits);
return digits.toArray(new Integer[]{});
}
private static void collectDigits(int num, List<Integer> digits) {
if(num / 10 > 0) {
collectDigits(num / 10, digits);
}
digits.add(num % 10);
}
If you would like to maintain the order of the digits from least significant (index[0]) to most significant (index[n]), the following updated getDigits() is what you need:
/**
* split an integer into its individual digits
* NOTE: digits order is maintained - i.e. Least significant digit is at index[0]
* #param num positive integer
* #return array of digits
*/
public static Integer[] getDigits(int num) {
if (num < 0) { return new Integer[0]; }
List<Integer> digits = new ArrayList<Integer>();
collectDigits(num, digits);
Collections.reverse(digits);
return digits.toArray(new Integer[]{});
}
I haven't seen anybody use this method, but it worked for me and is short and sweet:
int num = 5542;
String number = String.valueOf(num);
for(int i = 0; i < number.length(); i++) {
int j = Character.digit(number.charAt(i), 10);
System.out.println("digit: " + j);
}
This will output:
digit: 5
digit: 5
digit: 4
digit: 2
I noticed that there are few example of using Java 8 stream to solve your problem but I think that this is the simplest one:
int[] intTab = String.valueOf(number).chars().map(Character::getNumericValue).toArray();
To be clear:
You use String.valueOf(number) to convert int to String, then chars() method to get an IntStream (each char from your string is now an Ascii number), then you need to run map() method to get a numeric values of the Ascii number. At the end you use toArray() method to change your stream into an int[] array.
I see all the answer are ugly and not very clean.
I suggest you use a little bit of recursion to solve your problem. This post is very old, but it might be helpful to future coders.
public static void recursion(int number) {
if(number > 0) {
recursion(number/10);
System.out.printf("%d ", (number%10));
}
}
Output:
Input: 12345
Output: 1 2 3 4 5
simple solution
public static void main(String[] args) {
int v = 12345;
while (v > 0){
System.out.println(v % 10);
v /= 10;
}
}
// could be any num this is a randomly generated one
int num = (int) (Math.random() * 1000);
// this will return each number to a int variable
int num1 = num % 10;
int num2 = num / 10 % 10;
int num3 = num /100 % 10;
// you could continue this pattern for 4,5,6 digit numbers
// dont need to print you could then use the new int values man other ways
System.out.print(num1);
System.out.print("\n" + num2);
System.out.print("\n" + num3);
Since I don't see a method on this question which uses Java 8, I'll throw this in. Assuming that you're starting with a String and want to get a List<Integer>, then you can stream the elements like so.
List<Integer> digits = digitsInString.chars()
.map(Character::getNumericValue)
.boxed()
.collect(Collectors.toList());
This gets the characters in the String as a IntStream, maps those integer representations of characters to a numeric value, boxes them, and then collects them into a list.
Java 9 introduced a new Stream.iterate method which can be used to generate a stream and stop at a certain condition. This can be used to get all the digits in the number, using the modulo approach.
int[] a = IntStream.iterate(123400, i -> i > 0, i -> i / 10).map(i -> i % 10).toArray();
Note that this will get the digits in reverse order, but that can be solved either by looping through the array backwards (sadly reversing an array is not that simple), or by creating another stream:
int[] b = IntStream.iterate(a.length - 1, i -> i >= 0, i -> i - 1).map(i -> a[i]).toArray();
or
int[] b = IntStream.rangeClosed(1, a.length).map(i -> a[a.length - i]).toArray();
As an example, this code:
int[] a = IntStream.iterate(123400, i -> i > 0, i -> i / 10).map(i -> i % 10).toArray();
int[] b = IntStream.iterate(a.length - 1, i -> i >= 0, i -> i - 1).map(i -> a[i]).toArray();
System.out.println(Arrays.toString(a));
System.out.println(Arrays.toString(b));
Will print:
[0, 0, 4, 3, 2, 1]
[1, 2, 3, 4, 0, 0]
Easier way I think is to convert the number to string and use substring to extract and then convert to integer.
Something like this:
int digits1 =Integer.parseInt( String.valueOf(201432014).substring(0,4));
System.out.println("digits are: "+digits1);
ouput is
2014
I wrote a program that demonstrates how to separate the digits of an integer using a more simple and understandable approach that does not involve arrays, recursions, and all that fancy schmancy. Here is my code:
int year = sc.nextInt(), temp = year, count = 0;
while (temp>0)
{
count++;
temp = temp / 10;
}
double num = Math.pow(10, count-1);
int i = (int)num;
for (;i>0;i/=10)
{
System.out.println(year/i%10);
}
Suppose your input is the integer 123, the resulting output will be as follows:
1
2
3
Here is my answer, I did it for myself and I hope it's simple enough for those who don't want to use the String approach or need a more math-y solution:
public static void reverseNumber2(int number) {
int residual=0;
residual=number%10;
System.out.println(residual);
while (residual!=number) {
number=(number-residual)/10;
residual=number%10;
System.out.println(residual);
}
}
So I just get the units, print them out, substract them from the number, then divide that number by 10 - which is always without any floating stuff, since units are gone, repeat.
Java 8 solution to get digits as int[] from an integer that you have as a String:
int[] digits = intAsString.chars().map(i -> i - '0').toArray();
neither chars() nor codePoints() — the other lambda
String number = Integer.toString( 1100 );
IntStream.range( 0, number.length() ).map( i -> Character.digit( number.codePointAt( i ), 10 ) ).toArray(); // [1, 1, 0, 0]
Why don't you do:
String number = String.valueOf(input);
char[] digits = number.toCharArray();
Try this one.
const check = (num) => {
let temp = num
let result = []
while(temp > 0){
let a = temp%10;
result.push(a);
temp = (temp-a)/10;
}
return result;
}
check(98) //[ 8, 9 ]
public int[] getDigitsOfANumber(int number) {
String numStr = String.valueOf(number);
int retArr[] = new int[numStr.length()];
for (int i = 0; i < numStr.length(); i++) {
char c = numStr.charAt(i);
int digit = c;
int zero = (char) '0';
retArr[i] = digit - zero;
}
return retArr;
}
Integer.toString(1100) gives you the integer as a string. Integer.toString(1100).getBytes() to get an array of bytes of the individual digits.
Edit:
You can convert the character digits into numeric digits, thus:
String string = Integer.toString(1234);
int[] digits = new int[string.length()];
for(int i = 0; i<string.length(); ++i){
digits[i] = Integer.parseInt(string.substring(i, i+1));
}
System.out.println("digits:" + Arrays.toString(digits));
This uses the modulo 10 method to figure out each digit in a number greater than 0, then this will reverse the order of the array. This is assuming you are not using "0" as a starting digit.
This is modified to take in user input.
This array is originally inserted backwards, so I had to use the Collections.reverse() call to put it back into the user's order.
Scanner scanNumber = new Scanner(System.in);
int userNum = scanNumber.nextInt(); // user's number
// divides each digit into its own element within an array
List<Integer> checkUserNum = new ArrayList<Integer>();
while(userNum > 0) {
checkUserNum.add(userNum % 10);
userNum /= 10;
}
Collections.reverse(checkUserNum); // reverses the order of the array
System.out.print(checkUserNum);
Just to build on the subject, here's how to confirm that the number is a palindromic integer in Java:
public static boolean isPalindrome(int input) {
List<Integer> intArr = new ArrayList();
int procInt = input;
int i = 0;
while(procInt > 0) {
intArr.add(procInt%10);
procInt = procInt/10;
i++;
}
int y = 0;
int tmp = 0;
int count = 0;
for(int j:intArr) {
if(j == 0 && count == 0) {
break;
}
tmp = j + (tmp*10);
count++;
}
if(input != tmp)
return false;
return true;
}
I'm sure I can simplify this algo further. Yet, this is where I am. And it has worked under all of my test cases.
I hope this helps someone.
int number = 12344444; // or it Could be any valid number
int temp = 0;
int divider = 1;
for(int i =1; i< String.valueOf(number).length();i++)
{
divider = divider * 10;
}
while (divider >0) {
temp = number / divider;
number = number % divider;
System.out.print(temp +" ");
divider = divider/10;
}
Try this:
int num= 4321
int first = num % 10;
int second = ( num - first ) % 100 / 10;
int third = ( num - first - second ) % 1000 / 100;
int fourth = ( num - first - second - third ) % 10000 / 1000;
You will get first = 1, second = 2, third = 3 and fourth = 4 ....
Something like this will return the char[]:
public static char[] getTheDigits(int value){
String str = "";
int number = value;
int digit = 0;
while(number>0){
digit = number%10;
str = str + digit;
System.out.println("Digit:" + digit);
number = number/10;
}
return str.toCharArray();
}
As a noob, my answer would be:
String number = String.valueOf(ScannerObjectName.nextInt());
int[] digits = new int[number.length()];
for (int i = 0 ; i < number.length() ; i++)
int[i] = Integer.parseInt(digits.substring(i,i+1))
Now all the digits are contained in the "digits" array.
if digit is meant to be a Character
String numstr = Integer.toString( 123 );
Pattern.compile( "" ).splitAsStream( numstr ).map(
s -> s.charAt( 0 ) ).toArray( Character[]::new ); // [1, 2, 3]
and the following works correctly
numstr = "000123" gets [0, 0, 0, 1, 2, 3]
numstr = "-123" gets [-, 1, 2, 3]
A .NET solution using LINQ.
List<int> numbers = number.ToString().Select(x => x - 48).ToList();
I think this will be the most useful way to get digits:
public int[] getDigitsOf(int num)
{
int digitCount = Integer.toString(num).length();
if (num < 0)
digitCount--;
int[] result = new int[digitCount];
while (digitCount-- >0) {
result[digitCount] = num % 10;
num /= 10;
}
return result;
}
Then you can get digits in a simple way:
int number = 12345;
int[] digits = getDigitsOf(number);
for (int i = 0; i < digits.length; i++) {
System.out.println(digits[i]);
}
or more simply:
int number = 12345;
for (int i = 0; i < getDigitsOf(number).length; i++) {
System.out.println( getDigitsOf(number)[i] );
}
Notice the last method calls getDigitsOf method too much time. So it will be slower. You should create an int array and then call the getDigitsOf method once, just like in second code block.
In the following code, you can reverse to process. This code puts all digits together to make the number:
public int digitsToInt(int[] digits)
{
int digitCount = digits.length;
int result = 0;
for (int i = 0; i < digitCount; i++) {
result = result * 10;
result += digits[i];
}
return result;
}
Both methods I have provided works for negative numbers too.
see bellow my proposal with comments
int size=i.toString().length(); // the length of the integer (i) we need to split;
ArrayList<Integer> li = new ArrayList<Integer>(); // an ArrayList in whcih to store the resulting digits
Boolean b=true; // control variable for the loop in which we will reatrive step by step the digits
String number="1"; // here we will add the leading zero depending on the size of i
int temp; // the resulting digit will be kept by this temp variable
for (int j=0; j<size; j++){
number=number.concat("0");
}
Integer multi = Integer.valueOf(number); // the variable used for dividing step by step the number we received
while(b){
multi=multi/10;
temp=i/(multi);
li.add(temp);
i=i%(multi);
if(i==0){
b=false;
}
}
for(Integer in: li){
System.out.print(in.intValue()+ " ");
}
import java.util.Scanner;
class Test
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int num=sc.nextInt();
System.out.println("Enter a number (-1 to end):"+num);
int result=0;
int i=0;
while(true)
{
int n=num%10;
if(n==-1){
break;
}
i++;
System.out.println("Digit"+i+" = "+n);
result=result*10+n;
num=num/10;
if(num==0)
{
break;
}
}
}
}
I am a beginner(first year uni student) programmer trying to solve this problem which i'm finding somewhat difficult. If you are to answer this question, don't provide me with a complex daunting algorithm that will leave me scratching my head. I'll really appreciate it if you explain it step my step (both logically/conceptually then through code)
The problem is as follows:image
I have tried to attempt it and my code only works for a certain case that i tested.
package com.company;
import java.lang.Math;
public class Main {
public static int[][] binary_partition(int array[], int k){
int x = (int) Math.pow(2,k);
int[][] partition = new int[((array.length/x)*2)][array.length/x];
int divisor = array.length/x;
if ((array.length % 2) != 0){
return partition;
}
if (divisor >= array.length-1){
return partition;
}
if (k==1){
return partition;
}
int p = 0;
for(int i=0;i<((array.length/x)*2);i++)
{
for (int j = 0; j<array.length/x;j++)
{
partition[i][j] = array[p];
p += 1;
}
}
return partition;
}
public static void main(String[] args){
int[] array = {3, 2, 4, 7, 8, 9, 2, 3};
int[][] result = binary_partition(array,2);
for (int[] x : result){
for (int y : x)
{
System.out.print(y + " ");
}
System.out.println();
}
}
}
Your question is unclear, but this solution creates a function that partitions an array with the right length into 2^k sets.
First, an interesting fact: using the bitshift operator << on an integer increases its value by a power of two. So to find out the size of your partition, you could write
int numPartitions = 1 << k; // Equivalent to getting the integer value of 2^k
With this fact, the function becomes
public static int[][] partition(int[] set, int k) {
if (set == null)
return null; // Don't try to partition a null reference
// If k = 0, the partition of the set is just the set
if (k == 0) {
int[][] partition = new int[1][set.length];
// Copy the original set into the partition
System.arraycopy(set, 0, partition[0], 0, set.length);
return partition;
}
int numPartitions = 1 << k; // The number of sets to partition the array into
int numElements = set.length / numPartitions; // The number of elements per partition
/* Check if the set has enough elements to create a partition and make sure
that the partitions are even */
if (numElements == 0 || set.length % numElements != 0)
return null; // Replace with an error/exception of your choice
int[][] partition = new int[numPartitions][numElements];
int index = 0;
for (int r = 0; r < numPartitions; r++) {
for (int c = 0; c < numElements; c++) {
partition[r][c] = set[index++]; // Assign an element to the partition
}
}
return partition;
}
There are a few lines of your code where the intention is not clear. For example, it is not clear why you are validating divisor >= array.length-1. Checking k==1 is also incorrect because k=1 is a valid input to the method. In fact, all your validation checks are not needed. All you need to validate is that array.length is divisible by x.
The main problem that you have seems to be that you mixed up the lengths of the resulting array.
The resulting array should have a length of array.length / x, and each of the subarrays should have a length of x, hence:
int[][] partition = new int[array.length/x][x];
If you also fix your bounds on the for loops, your code should work.
Your nested for loop can be rewritten as a single for loop:
for(int i = 0 ; i < array.length ; i++)
{
int index = i / x;
int subArrayIndex = i % x;
partition[index][subArrayIndex] = array[i];
}
You just need to figure out which indices a an element array[i] belongs by dividing and getting the remainder.
I'm trying to calculate the total, mean and median of an array thats populated by input received by a textfield. I've managed to work out the total and the mean, I just can't get the median to work. I think the array needs to be sorted before I can do this, but I'm not sure how to do this. Is this the problem, or is there another one that I didn't find? Here is my code:
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.*;
import java.awt.event.*;
public class whileloopq extends Applet implements ActionListener
{
Label label;
TextField input;
int num;
int index;
int[] numArray = new int[20];
int sum;
int total;
double avg;
int median;
public void init ()
{
label = new Label("Enter numbers");
input = new TextField(5);
add(label);
add(input);
input.addActionListener(this);
index = 0;
}
public void actionPerformed (ActionEvent ev)
{
int num = Integer.parseInt(input.getText());
numArray[index] = num;
index++;
if (index == 20)
input.setEnabled(false);
input.setText("");
sum = 0;
for (int i = 0; i < numArray.length; i++)
{
sum += numArray[i];
}
total = sum;
avg = total / index;
median = numArray[numArray.length/2];
repaint();
}
public void paint (Graphics graf)
{
graf.drawString("Total = " + Integer.toString(total), 25, 85);
graf.drawString("Average = " + Double.toString(avg), 25, 100);
graf.drawString("Median = " + Integer.toString(median), 25, 115);
}
}
The Arrays class in Java has a static sort function, which you can invoke with Arrays.sort(numArray).
Arrays.sort(numArray);
double median;
if (numArray.length % 2 == 0)
median = ((double)numArray[numArray.length/2] + (double)numArray[numArray.length/2 - 1])/2;
else
median = (double) numArray[numArray.length/2];
Sorting the array is unnecessary and inefficient. There's a variation of the QuickSort (QuickSelect) algorithm which has an average run time of O(n); if you sort first, you're down to O(n log n). It actually finds the nth smallest item in a list; for a median, you just use n = half the list length. Let's call it quickNth (list, n).
The concept is that to find the nth smallest, choose a 'pivot' value. (Exactly how you choose it isn't critical; if you know the data will be thoroughly random, you can take the first item on the list.)
Split the original list into three smaller lists:
One with values smaller than the pivot.
One with values equal to the pivot.
And one with values greater than the pivot.
You then have three cases:
The "smaller" list has >= n items. In that case, you know that the nth smallest is in that list. Return quickNth(smaller, n).
The smaller list has < n items, but the sum of the lengths of the smaller and equal lists have >= n items. In this case, the nth is equal to any item in the "equal" list; you're done.
n is greater than the sum of the lengths of the smaller and equal lists. In that case, you can essentially skip over those two, and adjust n accordingly. Return quickNth(greater, n - length(smaller) - length(equal)).
Done.
If you're not sure that the data is thoroughly random, you need to be more sophisticated about choosing the pivot. Taking the median of the first value in the list, the last value in the list, and the one midway between the two works pretty well.
If you're very unlucky with your choice of pivots, and you always choose the smallest or highest value as your pivot, this takes O(n^2) time; that's bad. But, it's also very unlikely if you choose your pivot with a decent algorithm.
Sample code:
import java.util.*;
public class Utility {
/****************
* #param coll an ArrayList of Comparable objects
* #return the median of coll
*****************/
public static <T extends Number> double median(ArrayList<T> coll, Comparator<T> comp) {
double result;
int n = coll.size()/2;
if (coll.size() % 2 == 0) // even number of items; find the middle two and average them
result = (nth(coll, n-1, comp).doubleValue() + nth(coll, n, comp).doubleValue()) / 2.0;
else // odd number of items; return the one in the middle
result = nth(coll, n, comp).doubleValue();
return result;
} // median(coll)
/*****************
* #param coll a collection of Comparable objects
* #param n the position of the desired object, using the ordering defined on the list elements
* #return the nth smallest object
*******************/
public static <T> T nth(ArrayList<T> coll, int n, Comparator<T> comp) {
T result, pivot;
ArrayList<T> underPivot = new ArrayList<>(), overPivot = new ArrayList<>(), equalPivot = new ArrayList<>();
// choosing a pivot is a whole topic in itself.
// this implementation uses the simple strategy of grabbing something from the middle of the ArrayList.
pivot = coll.get(n/2);
// split coll into 3 lists based on comparison with the pivot
for (T obj : coll) {
int order = comp.compare(obj, pivot);
if (order < 0) // obj < pivot
underPivot.add(obj);
else if (order > 0) // obj > pivot
overPivot.add(obj);
else // obj = pivot
equalPivot.add(obj);
} // for each obj in coll
// recurse on the appropriate list
if (n < underPivot.size())
result = nth(underPivot, n, comp);
else if (n < underPivot.size() + equalPivot.size()) // equal to pivot; just return it
result = pivot;
else // everything in underPivot and equalPivot is too small. Adjust n accordingly in the recursion.
result = nth(overPivot, n - underPivot.size() - equalPivot.size(), comp);
return result;
} // nth(coll, n)
public static void main (String[] args) {
Comparator<Integer> comp = Comparator.naturalOrder();
Random rnd = new Random();
for (int size = 1; size <= 10; size++) {
ArrayList<Integer> coll = new ArrayList<>(size);
for (int i = 0; i < size; i++)
coll.add(rnd.nextInt(100));
System.out.println("Median of " + coll.toString() + " is " + median(coll, comp));
} // for a range of possible input sizes
} // main(args)
} // Utility
If you want to use any external library here is Apache commons math library using you can calculate the Median.
For more methods and use take look at the API documentation
import org.apache.commons.math3.*;
.....
......
........
//calculate median
public double getMedian(double[] values){
Median median = new Median();
double medianValue = median.evaluate(values);
return medianValue;
}
.......
For more on evaluate method AbstractUnivariateStatistic#evaluate
Update
Calculate in program
Generally, median is calculated using the following two formulas given here
If n is odd then Median (M) = value of ((n + 1)/2)th item term.
If n is even then Median (M) = value of [((n)/2)th item term + ((n)/2 + 1)th item term ]/2
In your program you have numArray, first you need to sort array using Arrays#sort
Arrays.sort(numArray);
int middle = numArray.length/2;
int medianValue = 0; //declare variable
if (numArray.length%2 == 1)
medianValue = numArray[middle];
else
medianValue = (numArray[middle-1] + numArray[middle]) / 2;
Arrays.sort(numArray);
return (numArray[size/2] + numArray[(size-1)/2]) / 2;
Arrays.sort(numArray);
int middle = ((numArray.length) / 2);
if(numArray.length % 2 == 0){
int medianA = numArray[middle];
int medianB = numArray[middle-1];
median = (medianA + medianB) / 2;
} else{
median = numArray[middle + 1];
}
EDIT: I initially had medianB setting to middle+1 in the even length arrays, this was wrong due to arrays starting count at 0. I have updated it to use middle-1 which is correct and should work properly for an array with an even length.
You can find good explanation at https://www.youtube.com/watch?time_continue=23&v=VmogG01IjYc
The idea it to use 2 Heaps viz one max heap and mean heap.
class Heap {
private Queue<Integer> low = new PriorityQueue<>(Comparator.reverseOrder());
private Queue<Integer> high = new PriorityQueue<>();
public void add(int number) {
Queue<Integer> target = low.size() <= high.size() ? low : high;
target.add(number);
balance();
}
private void balance() {
while(!low.isEmpty() && !high.isEmpty() && low.peek() > high.peek()) {
Integer lowHead= low.poll();
Integer highHead = high.poll();
low.add(highHead);
high.add(lowHead);
}
}
public double median() {
if(low.isEmpty() && high.isEmpty()) {
throw new IllegalStateException("Heap is empty");
} else {
return low.size() == high.size() ? (low.peek() + high.peek()) / 2.0 : low.peek();
}
}
}
Try sorting the array first. Then after it's sorted, if the array has an even amount of elements the mean of the middle two is the median, if it has a odd number, the middle element is the median.
Use Arrays.sort and then take the middle element (in case the number n of elements in the array is odd) or take the average of the two middle elements (in case n is even).
public static long median(long[] l)
{
Arrays.sort(l);
int middle = l.length / 2;
if (l.length % 2 == 0)
{
long left = l[middle - 1];
long right = l[middle];
return (left + right) / 2;
}
else
{
return l[middle];
}
}
Here are some examples:
#Test
public void evenTest()
{
long[] l = {
5, 6, 1, 3, 2
};
Assert.assertEquals((3 + 4) / 2, median(l));
}
#Test
public oddTest()
{
long[] l = {
5, 1, 3, 2, 4
};
Assert.assertEquals(3, median(l));
}
And in case your input is a Collection, you might use Google Guava to do something like this:
public static long median(Collection<Long> numbers)
{
return median(Longs.toArray(numbers)); // requires import com.google.common.primitives.Longs;
}
I was looking at the same statistics problems. The approach you are thinking it is good and it will work. (Answer to the sorting has been given)
But in case you are interested in algorithm performance, I think there are a couple of algorithms that have better performance than just sorting the array, one (QuickSelect) is indicated by #bruce-feist's answer and is very well explained.
[Java implementation: https://discuss.leetcode.com/topic/14611/java-quick-select ]
But there is a variation of this algorithm named median of medians, you can find a good explanation on this link:
http://austinrochford.com/posts/2013-10-28-median-of-medians.html
Java implementation of this:
- https://stackoverflow.com/a/27719796/957979
I faced a similar problem yesterday.
I wrote a method with Java generics in order to calculate the median value of every collection of Numbers; you can apply my method to collections of Doubles, Integers, Floats and returns a double. Please consider that my method creates another collection in order to not alter the original one.
I provide also a test, have fun. ;-)
public static <T extends Number & Comparable<T>> double median(Collection<T> numbers){
if(numbers.isEmpty()){
throw new IllegalArgumentException("Cannot compute median on empty collection of numbers");
}
List<T> numbersList = new ArrayList<>(numbers);
Collections.sort(numbersList);
int middle = numbersList.size()/2;
if(numbersList.size() % 2 == 0){
return 0.5 * (numbersList.get(middle).doubleValue() + numbersList.get(middle-1).doubleValue());
} else {
return numbersList.get(middle).doubleValue();
}
}
JUnit test code snippet:
/**
* Test of median method, of class Utils.
*/
#Test
public void testMedian() {
System.out.println("median");
Double expResult = 3.0;
Double result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,13.0));
assertEquals(expResult, result);
expResult = 3.5;
result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,4.0,13.0));
assertEquals(expResult, result);
}
Usage example (consider the class name is Utils):
List<Integer> intValues = ... //omitted init
Set<Float> floatValues = ... //omitted init
.....
double intListMedian = Utils.median(intValues);
double floatSetMedian = Utils.median(floatValues);
Note: my method works on collections, you can convert arrays of numbers to list of numbers as pointed here
And nobody paying attention when list contains only one element (list.size == 1). All your answers will crash with index out of bound exception, because integer division returns zero (1 / 2 = 0). Correct answer (in Kotlin):
MEDIAN("MEDIAN") {
override fun calculate(values: List<BigDecimal>): BigDecimal? {
if (values.size == 1) {
return values.first()
}
if (values.size > 1) {
val valuesSorted = values.sorted()
val mid = valuesSorted.size / 2
return if (valuesSorted.size % 2 != 0) {
valuesSorted[mid]
} else {
AVERAGE.calculate(listOf(valuesSorted[mid - 1], valuesSorted[mid]))
}
}
return null
}
},
As #Bruce-Feist mentions, for a large number of elements, I'd avoid any solution involving sort if performance is something you are concerned about. A different approach than those suggested in the other answers is Hoare's algorithm to find the k-th smallest of element of n items. This algorithm runs in O(n).
public int findKthSmallest(int[] array, int k)
{
if (array.length < 10)
{
Arrays.sort(array);
return array[k];
}
int start = 0;
int end = array.length - 1;
int x, temp;
int i, j;
while (start < end)
{
x = array[k];
i = start;
j = end;
do
{
while (array[i] < x)
i++;
while (x < array[j])
j--;
if (i <= j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
} while (i <= j);
if (j < k)
start = i;
if (k < i)
end = j;
}
return array[k];
}
And to find the median:
public int median(int[] array)
{
int length = array.length;
if ((length & 1) == 0) // even
return (findKthSmallest(array, array.length / 2) + findKthSmallest(array, array.length / 2 + 1)) / 2;
else // odd
return findKthSmallest(array, array.length / 2);
}
public static int median(int[] arr) {
int median = 0;
java.util.Arrays.sort(arr);
for (int i=0;i<arr.length;i++) {
if (arr.length % 2 == 1) {
median = Math.round(arr[arr.length/2]);
} else {
median = (arr[(arr.length/2)] + arr[(arr.length/2)-1])/2;
}
}
return median;
}
Check out the Arrays.sort methods:
http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html
You should also really abstract finding the median into its own method, and just return the value to the calling method. This will make testing your code much easier.
public int[] data={31, 29, 47, 48, 23, 30, 21
, 40, 23, 39, 47, 47, 42, 44, 23, 26, 44, 32, 20, 40};
public double median()
{
Arrays.sort(this.data);
double result=0;
int size=this.data.length;
if(size%2==1)
{
result=data[((size-1)/2)+1];
System.out.println(" uneven size : "+result);
}
else
{
int middle_pair_first_index =(size-1)/2;
result=(data[middle_pair_first_index+1]+data[middle_pair_first_index])/2;
System.out.println(" Even size : "+result);
}
return result;
}
package arrays;
public class Arraymidleelement {
static public double middleArrayElement(int [] arr)
{
double mid;
if(arr.length%2==0)
{
mid=((double)arr[arr.length/2]+(double)arr[arr.length/2-1])/2;
return mid;
}
return arr[arr.length/2];
}
public static void main(String[] args) {
int arr[]= {1,2,3,4,5,6};
System.out.println( middleArrayElement(arr));
}
}
I am trying to implement a coin problem, Problem specification is like this
Create a function to count all possible combination of coins which can be used for given amount.
All possible combinations for given amount=15, coin types=1 6 7
1) 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2) 1,1,1,1,1,1,1,1,1,6,
3) 1,1,1,1,1,1,1,1,7,
4) 1,1,1,6,6,
5) 1,1,6,7,
6) 1,7,7,
function prototype:
int findCombinationsCount(int amount, int coins[])
assume that coin array is sorted. for above example this function should return 6.
Anyone guide me how to implement this??
Use recursion.
int findCombinationsCount(int amount, int coins[]) {
return findCombinationsCount(amount, coins, 0);
}
int findCombinationsCount(int amount, int coins[], int checkFromIndex) {
if (amount == 0)
return 1;
else if (amount < 0 || coins.length == checkFromIndex)
return 0;
else {
int withFirstCoin = findCombinationsCount(amount-coins[checkFromIndex], coins, checkFromIndex);
int withoutFirstCoin = findCombinationsCount(amount, coins, checkFromIndex+1);
return withFirstCoin + withoutFirstCoin;
}
}
You should check this implementation though. I don't have a Java IDE here, and I'm a little rusty, so it may have some errors.
Although recursion can work and is often an assignment to implement in some college level courses on Algorithms & Data Structures, I believe the "dynamic programming" implementation is more efficient.
public static int findCombinationsCount(int sum, int vals[]) {
if (sum < 0) {
return 0;
}
if (vals == null || vals.length == 0) {
return 0;
}
int dp[] = new int[sum + 1];
dp[0] = 1;
for (int i = 0; i < vals.length; ++i) {
for (int j = vals[i]; j <= sum; ++j) {
dp[j] += dp[j - vals[i]];
}
}
return dp[sum];
}
You can use generating function methods to give fast algorithms, which use complex numbers.
Given the coin values c1, c2, .., ck, to get the number of ways to sum n, what you need is the coefficient of x^n in
(1 + x^c1 + x^(2c1) + x^(3c1) + ...)(1+x^c2 + x^(2c2) + x^(3c2) + ...)....(1+x^ck + x^(2ck) + x^(3ck) + ...)
Which is the same as finding the coefficient of x^n in
1/(1-x^c1) * 1/(1-x^c2) * ... * (1-x^ck)
Now using complex numbers, x^a - 1 = (x-w1)(x-w2)...(x-wa) where w1, w2 etc are the complex roots of unity.
So
1/(1-x^c1) * 1/(1-x^c2) * ... * (1-x^ck)
can be written as
1/(x-a1)(x-a2)....(x-am)
which can be rewritten using partial fractions are
A1/(x-a1) + A2/(x-a2) + ... + Am/(x-am)
The coefficient of x^n in this can be easily found:
A1/(a1)^(n+1) + A2/(a2)^(n+1) + ...+ Am/(am)^(n+1).
A computer program should easily be able to find Ai and ai (which could be complex numbers). Of course, this might involve floating point computations.
For large n, this will be probably faster than enumerating all the possible combinations.
Hope that helps.
Very simple with recursion:
def countChange(money: Int, coins: List[Int]): Int = {
def reduce(money: Int, coins: List[Int], accCounter: Int): Int = {
if(money == 0) accCounter + 1
else if(money < 0 || coins.isEmpty) accCounter
else reduce(money - coins.head, coins, accCounter) + reduce(money, coins.tail, accCounter)
}
if(money <= 0 || coins.isEmpty) 0
else reduce(money, coins, 0)
}
This is example in SCALA
Aryabhatta’s answer for
counting the number of ways to make change with coins of fixed
denominations is very cute but also impractical to implement as
described. Rather than use complex numbers, we’ll use modular
arithmetic, similar to how the number-theoretic transform replaces a
Fourier transform for multiplying integer polynomials.
Let D be the least common multiple of the coin denominations. By
Dirichlet’s theorem on arithmetic progressions, there exist infinitely
many prime numbers p such that D divides p - 1. (With any luck,
they’ll even be distributed in a way such that we can find them
efficiently.) We’ll compute the number of ways modulo some p
satisfying this condition. By obtaining a crude bound somehow (e.g.,
n + k - 1 choose k - 1 where n is the total and k is the number
of denominations), repeating this procedure with several different
primes whose product exceeds that bound, and applying the Chinese
remainder theorem, we can recover the exact number.
Test candidates 1 + k*D for integers k > 0 until we find a prime
p. Let g be a primitive root modulo p (generate candidates at
random and apply the standard test). For each denomination d, express
the polynomial x**d - 1 modulo p as a product of factors:
x**d - 1 = product from i=0 to d-1 of (x - g**((p-1)*i/d)) [modulo p].
Note that d divides D divides p-1, so the exponent indeed is an
integer.
Let m be the sum of denominations. Gather all of the constants
g**((p-1)*i/d) as a(0), ..., a(m-1). The next step is to find a
partial fraction decomposition A(0), ..., A(m-1) such that
sign / product from j=0 to m-1 of (a(j) - x) =
sum from j=0 to m-1 of A(j)/(a(j) - x) [modulo p],
where sign is 1 if there are an even number of denominations and
-1 if there are an odd number of denominations. Derive a system of
linear equations for A(j) by evaluating both sides of the given
equation for different values of x, then solve it with Gaussian
elimination. Life gets complicated if there are duplicates; it's probably easiest just to pick another prime.
Given this setup, we can compute the number of ways (modulo p, of
course) to make change amounting to n as
sum from j=0 to m-1 of A(j) * (1/a(j))**(n+1).
The recursive solutions mentioned will work, but they're going to be horrendously slow if you add more coin denominations and/or increase the target value significantly.
What you need to speed it up is to implement a dynamic programming solution. Have a look at the knapsack problem. You can adapt the DP solution mentioned there to solve your problem by keeping a count of the number of ways a total can be reached rather than the minimum number of coins required.
package algorithms;
import java.util.Random;
/**`enter code here`
* Owner : Ghodrat Naderi
* E-Mail: Naderi.ghodrat#gmail.com
* Date : 10/12/12
* Time : 4:50 PM
* IDE : IntelliJ IDEA 11
*/
public class CoinProblem
{
public static void main(String[] args)
{
int[] coins = {1, 3, 5, 10, 20, 50, 100, 200, 500};
int amount = new Random().nextInt(10000);
int coinsCount = 0;
System.out.println("amount = " + amount);
int[] numberOfCoins = findNumberOfCoins(coins, amount);
for (int i = 0; i < numberOfCoins.length; i++)
{
if (numberOfCoins[i] > 0)
{
System.out.println("coins= " + coins[i] + " Count=" + numberOfCoins[i] + "\n");
coinsCount += numberOfCoins[i];
}
}
System.out.println("numberOfCoins = " + coinsCount);
}
private static int[] findNumberOfCoins(int[] coins, int amount)
{
int c = coins.length;
int[] numberOfCoins = new int[coins.length];
while (amount > 0)
{
c--;
if (amount >= coins[c])
{
int quotient = amount / coins[c];
amount = amount - coins[c] * quotient;
numberOfCoins[c] = quotient;
}
}
return numberOfCoins;
}
}
A recursive solution might be the right answer here:
int findCombinationsCount(int amount, int coins[])
{
// I am assuming amount >= 0, coins.length > 0 and all elements of coins > 0.
if (coins.length == 1)
{
return amount % coins[0] == 0 ? 1 : 0;
}
else
{
int total = 0;
int[] subCoins = arrayOfCoinsExceptTheFirstOne(coins);
for (int i = 0 ; i * coins[0] <= amount ; ++i)
{
total += findCombinationsCount(amount - i * coins[0], subCoins);
}
return total;
}
}
Warning: I haven't tested or even compiled the above.
The solution provided by #Jordi is nice but runs extremely slow. You can try input 600 to that solution and see how slow it is.
My idea is to use bottom-up dynamic programming.
Note that generally, the possible combination for money=m and coins{a,b,c} equals combination for
m-c and coins{a,b,c} (with coin c)
combination for m and coins{a,b} (without coin c).
If no coins are available or available coins can not cover the required amount of money, it should fill in 0 to the block accordingly. If the amount of money is 0, it should fill in 1.
public static void main(String[] args){
int[] coins = new int[]{1,2,3,4,5};
int money = 600;
int[][] recorder = new int[money+1][coins.length];
for(int k=0;k<coins.length;k++){
recorder[0][k] = 1;
}
for(int i=1;i<=money;i++){
//System.out.println("working on money="+i);
int with = 0;
int without = 0;
for(int coin_index=0;coin_index<coins.length;coin_index++){
//System.out.println("working on coin until "+coins[coin_index]);
if(i-coins[coin_index]<0){
with = 0;
}else{
with = recorder[i-coins[coin_index]][coin_index];
}
//System.out.println("with="+with);
if(coin_index-1<0){
without = 0;
}else{
without = recorder[i][coin_index-1];
}
//System.out.println("without="+without);
//System.out.println("result="+(without+with));
recorder[i][coin_index] = with+without;
}
}
System.out.print(recorder[money][coins.length-1]);
}
This code is based on the solution provided by JeremyP which is working perfect and I just enhanced it to optimize the performance by using dynamic programming.I couldn't comment on the JeremyP post because I don't have enough reputation :)
public static long makeChange(int[] coins, int money) {
Long[][] resultMap = new Long[coins.length][money+1];
return getChange(coins,money,0,resultMap);
}
public static long getChange(int[] coins, int money, int index,Long[][] resultMap) {
if (index == coins.length -1) // if we are at the end
return money%coins[index]==0? 1:0;
else{
//System.out.printf("Checking index %d and money %d ",index,money);
Long storedResult =resultMap[index][money];
if(storedResult != null)
return storedResult;
long total=0;
for(int coff=0; coff * coins[index] <=money; coff ++){
total += getChange(coins, money - coff*coins[index],index +1,resultMap);
}
resultMap[index][money] = total;
return total;
}
}
First idea:
int combinations = 0;
for (int i = 0; i * 7 <=15; i++) {
for (int j = 0; j * 6 + i * 7 <= 15; j++) {
combinations++;
}
}
(the '<=' is superfluous in this case, but is needed for a more general solution, if you decide to change your parameters)
Below is recursion with memoization java solution. for below one we have 1,2,3,5 as coins and 200 as the target amount.
countCombinations(200,new int[]{5,2,3,1} , 0, 0,new Integer[6][200+5]);
static int countCombinations(Integer targetAmount, int[] V,int currentAmount, int coin, Integer[][] memory){
//Comment below if block if you want to see the perf difference
if(memory[coin][currentAmount] != null){
return memory[coin][currentAmount];
}
if(currentAmount > targetAmount){
memory[coin][currentAmount] = 0;
return 0;
}
if(currentAmount == targetAmount){
return 1;
}
int count = 0;
for(int selectedCoin : V){
if(selectedCoin >= coin){
count += countCombinations(targetAmount, V, currentAmount+selectedCoin, selectedCoin,memory);
}
}
memory[coin][currentAmount] = count;
return count;
}
#include<iostream>
using namespace std;
int solns = 0;
void countComb(int* arr, int low, int high, int Val)
{
bool b = false;
for (size_t i = low; i <= high; i++)
{
if (Val - arr[i] == 0)
{
solns++;
break;
}
else if (Val - arr[i] > 0)
countComb(arr, i, high, Val - arr[i]);
}
}
int main()
{
int coins[] = { 1,2,5 };
int value = 7;
int arrSize = sizeof(coins) / sizeof(int);
countComb(coins,0, arrSize,value);
cout << solns << endl;
return 0;
}
Again using recursion a tested solution, though probably not the most elegant code. (note it returns the number of each coin to use rather than repeating the actual coin ammount n times).
public class CoinPerm {
#Test
public void QuickTest() throws Exception
{
int ammount = 15;
int coins[] = {1,6,7};
ArrayList<solution> solutionList = SolvePerms(ammount, coins);
for (solution sol : solutionList)
{
System.out.println(sol);
}
assertTrue("Wrong number of solutions " + solutionList.size(),solutionList.size() == 6);
}
public ArrayList<solution> SolvePerms(int ammount, int coins[]) throws Exception
{
ArrayList<solution> solutionList = new ArrayList<solution>();
ArrayList<Integer> emptyList = new ArrayList<Integer>();
solution CurrentSolution = new solution(emptyList);
GetPerms(ammount, coins, CurrentSolution, solutionList);
return solutionList;
}
private void GetPerms(int ammount, int coins[], solution CurrentSolution, ArrayList<solution> mSolutions) throws Exception
{
int currentCoin = coins[0];
if (currentCoin <= 0)
{
throw new Exception("Cant cope with negative or zero ammounts");
}
if (coins.length == 1)
{
if (ammount % currentCoin == 0)
{
CurrentSolution.add(ammount/currentCoin);
mSolutions.add(CurrentSolution);
}
return;
}
// work out list with one less coin.
int coinsDepth = coins.length;
int reducedCoins[] = new int[(coinsDepth -1 )];
for (int j = 0; j < coinsDepth - 1;j++)
{
reducedCoins[j] = coins[j+1];
}
// integer rounding okay;
int numberOfPerms = ammount / currentCoin;
for (int j = 0; j <= numberOfPerms; j++)
{
solution newSolution = CurrentSolution.clone();
newSolution.add(j);
GetPerms(ammount - j * currentCoin,reducedCoins, newSolution, mSolutions );
}
}
private class solution
{
ArrayList<Integer> mNumberOfCoins;
solution(ArrayList<Integer> anumberOfCoins)
{
mNumberOfCoins = anumberOfCoins;
}
#Override
public String toString() {
if (mNumberOfCoins != null && mNumberOfCoins.size() > 0)
{
String retval = mNumberOfCoins.get(0).toString();
for (int i = 1; i< mNumberOfCoins.size();i++)
{
retval += ","+mNumberOfCoins.get(i).toString();
}
return retval;
}
else
{
return "";
}
}
#Override
protected solution clone()
{
return new solution((ArrayList<Integer>) mNumberOfCoins.clone());
}
public void add(int i) {
mNumberOfCoins.add(i);
}
}
}
Dynamic Programming Solution
Given an array of denominations D = {d1, d2, d3, ... , dm} and a target amount W. Note that D doesn't need to be sorted.
Let T(i, j) be the number of combinations that make up amount j using only denominations on the left of the ith one (can include itself) in D.
We have:
T(0, 0) = 1 : since the amount is 0, there is only 1 valid combination that makes up 0, which is the empty set.
T(i, j) = T(i - 1, j) if D[i] > j
T(i, j) = T(i - 1, j) + T(i, j - D[i]) if D[i] <= j
public int change(int amount, int[] coins) {
int m = coins.length;
int n = amount;
int[][] dp = new int[m + 1][n + 1];
dp[0][0] = 1;
for (int i = 1; i <= m; i++) {
for (int j = 0; j <= n; j++) {
if (j < coins[i - 1]) {
dp[i][j] = dp[i - 1][j];
}
else {
dp[i][j] = dp[i - 1][j] + dp[i][j - coins[i - 1]];
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
int b,c,total = 15;
int combos =1;
for(int d=0;d<total/7;d++)
{
b = total - d * 7;
for (int n = 0; n <= b /6; n++)
{
combos++;
}
}
System.out.print("TOTAL COMBINATIONS = "+combos);
}
Below is a recursive backtracking solution I created, It lists and counts all possible combination of denominations (coins) that would add up to a given amount.
Both denominations and the amounts can be dynamic
public class CoinComboGenerate {
public static final int[] DENO = {1,6,7};
public static final int AMOUNT = 15;
public static int count = 0;
public static void change(int amount) {
change(amount, new ArrayList<>(),0);
}
private static void change(int rem, List<Integer> coins, int pos) {
if (rem == 0) {
count++;
System.out.println(count+")"+coins);
return;
}
while(pos<DENO.length){
if (rem >= DENO[pos]) {
coins.add(DENO[pos]);
change(rem - DENO[pos], coins,pos);
coins.remove(coins.size() - 1); //backtrack
}
pos++;
}
}
public static void main(String[] args) {
change(AMOUNT);
}
}
Output:
1)[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
2)[1, 1, 1, 1, 1, 1, 1, 1, 1, 6]
3)[1, 1, 1, 1, 1, 1, 1, 1, 7]
4)[1, 1, 1, 6, 6]
5)[1, 1, 6, 7]
6)[1, 7, 7]
The same problem for coins(1,5,10,25,50) has one of below solutions.
The solution should satisfy below equation:
1*a + 5*b + 10*c + 25*d + 50*e == cents
public static void countWaysToProduceGivenAmountOfMoney(int cents) {
for(int a = 0;a<=cents;a++){
for(int b = 0;b<=cents/5;b++){
for(int c = 0;c<=cents/10;c++){
for(int d = 0;d<=cents/25;d++){
for(int e = 0;e<=cents/50;e++){
if(1*a + 5*b + 10*c + 25*d + 50*e == cents){
System.out.println("1 cents :"+a+", 5 cents:"+b+", 10 cents:"+c);
}
}
}
}
}
}
}
This can be modified for any general solutions.