Related
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 want to generate 4 random numbers and they can't have repeated digits.
For instance 4567, (it doesn't have a repeated value like 4557).
I want them to be random.
Is there any way to achieve this?
I'm obsessed with streams nowadays. But streams are pretty slow. To show the slowness I wrote following main method. "generateWithLoop" method covers #WJS's answer.
public static void main(String[] args) {
long nanoStart = System.nanoTime();
generateWithStreams();
long nanoEnd = System.nanoTime();
System.out.println("Elapsed time with Streams : " + (nanoEnd - nanoStart) + " nano seconds");
nanoStart = System.nanoTime();
generateWithLoop();
nanoEnd = System.nanoTime();
System.out.println("Elapsed time with Loop : " + (nanoEnd - nanoStart) + " nano seconds");
}
Console output :
Elapsed time with Streams : 81367089 nano seconds
Elapsed time with Loop : 75093 nano seconds
With stream :
public static void generateWithStreams() {
List<Integer> orderedList = getOrderedList();
for (int i = 0; i < 4; i++) {
List<Integer> shuffledList = getShuffledList(orderedList);
System.out.println(get4DigitNumber(shuffledList));
}
}
public static List<Integer> getOrderedList() {
return IntStream.range(0, 10).boxed().collect(Collectors.toList());
}
public static List<Integer> getShuffledList(List<Integer> list) {
return list.stream().sorted((o1, o2) -> ThreadLocalRandom.current().nextInt(-1, 2)).collect(Collectors.toList());
}
public static Integer get4DigitNumber(List<Integer> shuffledList) {
final Integer LIMIT = shuffledList.get(0).equals(0) ? 5 : 4;
return shuffledList.stream().limit(LIMIT).reduce(0, (sum, current) -> sum * 10 + current);
}
With loop :
public static void generateWithLoop() {
Random r = new Random();
for (int k = 0; k < 4; k++) {
int val = gen(r);
System.out.println(val);
}
}
static int[] base = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static int gen(Random r) {
int val = 0;
int s = 10;
for (int i = 0; i < 4; i++) {
int n = r.nextInt(s);
val = val * 10 + base[n];
int save = base[n];
base[n] = base[--s];
base[s] = save;
}
return val < 1000 ? val * 10 + base[r.nextInt(s)] : val;
}
This will generate 4 digit random numbers with no repeating digits.
It works by generating 4 unique digits in the same fashion that one might shuffle a deck of cards in a computer game. It then simply builds up the four digit number by multiplication and addition.
If the number is less than 1000, then that means a 0 was used and was at the beginning. So just choose another digit to adjust.
Random r = new Random();
for (int k = 0; k < 10; k++) {
int val = gen(r);
System.out.println(val);
}
static int[] base = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
public static int gen(Random r) {
int val = 0;
int s=10;
for (int i = 0; i < 4; i++) {
int n = r.nextInt(s);
val = val * 10 + base[n];
int save = base[n];
base[n] = base[--s];
base[s] = save;
}
return val < 1000 ? val * 10 + base[r.nextInt(s)] : val;
}
Here is a more straightforward way of doing it. The philosophy is the same as above. It may not be quite as efficient as the previous due to the shuffling of all the digits.
// generate four digit numbers that have distinct digits.
List<Integer> digits = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
Collections.shuffle(digits);
// now just use the first four of the shuffled list
if (digits.get(0) == 0) {
// for a 4 digit number, first digit can't be zero
// so choose another.
digits.set(0, digits.get(4));
}
// now use simple arithmetic to create the four digit number.
int n = 0;
for (int d : digits.subList(0,4)) {
n = n * 10 + d;
}
System.out.println(n);
public static void main(String[] args) {
List<Integer> list= new ArrayList<>();
for(int j = 0; j < 10; j++){
list.add(j);
}
Collections.shuffle(list);
String randomDigit= "";
for(int j = 0; j < 4; j++){
randomDigit+= list.get(j).toString();
}
System.out.println(randomDigit);
}
This is converting the string to int. But this will work you can use it.
Steps:
Create a List that will hold each individual number of the generated
4-digit number
Generate a random number for the units place between 1 and 9, and put it in the list
Create a loop to generate a random number between 0 and 9 for the
ten's place until the last place; and each time, put the random
number into your list. examine the number for each iteration that is not contained in your list
Eventually the size of the list is now 4; combine these 4 individuals into a String, and convert to Integer.
List<Integer> myNumber = new ArrayList<Integer>();
Random r = new Random();
// Generate a random number between 1 and 9 for units place
myNumber.add(r.nextInt(9) + 1);// adding 1 to avoid 0 in the units place
// Generate a random number between 0 and 9 for 10's and upcoming places
do {
Integer num = r.nextInt(10);
// Check the list doesn't contain that number
if (!myNumber.contains(num)) {
myNumber.add(num);
}
}while (myNumber.size() < 4);
StringBuilder numStr = new StringBuilder();
for (int i = 0; i < myNumber.size(); i++)
numStr.append(myNumber.get(i));
System.out.println(Integer.parseInt(numStr.toString()));
A solution using stream and Lambdas from Java-8 onwards:
public static void main(String[] args) {
Map<String, String> collect = IntStream.rangeClosed(1, 9).boxed()
.flatMap(x -> IntStream.rangeClosed(0, 9).boxed()
.flatMap(y -> IntStream.rangeClosed(0, 9).boxed()
.flatMap(z -> IntStream.rangeClosed(0, 9).boxed()
.flatMap(w -> IntStream.rangeClosed(1, 9).boxed().map(s -> s.toString()).filter(e -> noneRepete(x, y, z, w))
.map(k -> x.toString() + y.toString() + z.toString() + w.toString())))))
.collect(Collectors.toMap(Function.identity(), s -> s, (a, b) -> a));
collect.keySet().forEach(System.out::println);
}
public static boolean noneRepete(Integer a, Integer b, Integer c, Integer d) {
if (! a.equals(b) && ! a.equals(c) && ! a.equals(d) && a !=0) {
if (! b.equals(c) && ! b.equals(d)) {
return ! c.equals(d);
}
}
return false;
}
Explanation:
Here we are flattening the stream of Integers from 1 to 9(first digit cannot be 0).
while in further we are flattening stream of Integers from 0 to 9.
The above process goes 2 more time thus making it a four digit, we are having a custom filter which is making sure that all four digits are unique.
At last we are collecting them as keys and values making sure the digits are unique and key itself in a map is unique.
I am trying to write a method that creates and returns an array of random Integers that has a length of eight and is within the range [25, 725].
Every Integer in the array must be higher or lower than every other Integer in the array by at least 15. However, my method isn't returning arrays that meet this requirement.
I set up a main() method that checks the output of my method 100,000 times, and throws an Exception if there are any Integers that are too close.
How can I create a method that will return an array of Integers where the difference between every Integer and every other Integer is at least 15?
public class Test {
public static void main(String[] args) throws Exception {
Integer[] distances = new Integer[8];
for (int i = 0; i < 100000; i++) {
distances = createPlanetDistances(distances.length);
// check distances for values within 15
for (int x = 0; x < distances.length; x++) {
for (int y = 0; y < distances.length; y++) {
if (x == y)
continue;
if (Math.abs(distances[x] - distances[y]) < 15) {
System.out.println(distances[x] + " " + distances[y]);
throw new Exception("Doesn't work");
}
}
}
for (int distance : distances)
System.out.print(distance + " ");
System.out.println(System.lineSeparator());
}
}
/**
* Creates an array of distances-from-the-sun for a given number of Planets.
* It does not allow distances to be within 15 of any other distance.
*
* #param planetAmount The number of distances to return.
* #return An array of distances-from-the-sun.
*/
private static Integer[] createPlanetDistances(int planetAmount) {
SplittableRandom random = new SplittableRandom();
final int min = 25;
final int max = 726;
HashSet<Integer> distanceSet = new HashSet<>();
// make sure there are no duplicate Integers
for(int i = 0; i < planetAmount; i++) {
int num = random.nextInt(min, max);
while (distanceSet.contains(num))
num = random.nextInt(min, max);
distanceSet.add(num);
}
// make sure each distance is 15 away from all others
Integer[] distances = distanceSet.toArray(new Integer[]{});
for(int i = 0; i < distances.length; i++) {
// check distances[i] with all other Integers
for (int j = 0; j < distances.length; j++) {
// do not compare an element with itself
if (j == i)
continue;
int difference = Math.abs(distances[i] - distances[j]);
if (difference < 15) {
while (difference < 15) {
distances[i] = random.nextInt(min, max);
difference = Math.abs(distances[i] - distances[j]);
}
// check all Integers again
System.out.println("HERE " + i + " " + j);
i = 0;
break;
}
}
}
return distanceSet.toArray(new Integer[]{});
}
}
To find COUNT numbers in range MIN to MAX (exclusive) that are more than DISTANCE apart, build a TreeSet and use the ceiling(...) method to find nearby values.
Example
final int DISTANCE = 15, MIN = 25, MAX = 726, COUNT = 8;
ThreadLocalRandom random = ThreadLocalRandom.current();
TreeSet<Integer> numbers = new TreeSet<>();
while (numbers.size() < COUNT) {
int value = random.nextInt(MIN, MAX);
Integer ceiling = numbers.ceiling(value - DISTANCE);
if (ceiling == null || ceiling > value + DISTANCE)
numbers.add(value);
}
System.out.println(numbers);
Sample Output
[86, 104, 120, 369, 425, 532, 682, 713]
You can always shuffle the result if you don't want them in ascending order.
How It Works
The ceiling method returns the least value in the set greater than or equal to the given value, or null if there is no such value.
So if e.g. value is 134 and DISTANCE is 15, then ceiling(value - DISTANCE) will find the smallest value that is >= 119. If that value is >= 149, then we know the nearby range 119-149 is clear and we can use the 134 value.
You are generating planetary orbits, so it should be OK to have monotonically increasing numbers. Each number you generate has constraints imposed on it by the following numbers, and in turn imposes constraints on them once it is generated.
Constraint: If you want to generate N orbits between min and max separated by D, then your bounds for the first orbit are [min, max - D * (N - 1)]. This is simply because you can't pack the following N - 1 planets into a space that is less than D * (N - 1).
You can update the second constraint as you go, since the new minimum is going to be the last generated number + D. Here is a simple O(n) implementation (assuming that genrating a random number is O(1)):
final int DISTANCE = 15, MIN = 25, MAX = 726, COUNT = 8;
Random random = Random();
orbits = new int[COUNT];
if(MAX - MIN < DISTANCE * COUNT) {
throw new IllegalArgumentException("Insert pithy comment about COUNT");
}
min = MIN;
for(int i = 0; i < COUNT; i++) {
max = MAX - DISTANCE * (COUNT - i - 1);
orbits[i] = random.nextInt(max - min + 1) + min;
min = orbits[i] + DISTANCE;
}
The following approach avoids acceptance/rejection sampling by removing the spacing requirement, generating values uniformly over the correspondingly shortened range, adding the spacing gaps back, and shuffling to yield the results in a randomized order.
static Random r = new Random();
public static ArrayList<Integer>
gen_array(int lower_bound, int upper_bound, int n, int separation) {
upper_bound -= (n - 1) * separation;
if(upper_bound < lower_bound) {
throw new IllegalArgumentException("Infeasible arguments");
}
ArrayList<Integer> ary = new ArrayList<>();
while(ary.size() < n) {
ary.add(lower_bound + r.nextInt(upper_bound - lower_bound + 1));
}
Collections.sort(ary);
for (int i = 0; i < n; ++i) {
ary.set(i, ary.get(i) + i * separation);
}
Collections.shuffle(ary);
return ary;
}
If you call it with a value of 8 for n, a lower_bound of 25, an upper_bound of 130, and a separation of 15, it yields the correct result immediately where an acceptance/rejection approach could take an awful lot of iterations to cough up the unique set of values for the answer.
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);
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.