Find closest factor to a number, of a number - java

I am trying to automate the finding of the closest factor of a number to another number;
Example:
Closest factor of 700 to 30 is 28 (30 does not go into 700, but 28 does).
An obvious solution is just to get all the factors of 700 and do a simple distance calculation to find the nearest factor to 30, but this seems to be inefficient.
Another solution is to find all the base prime factors, like:
private List<Integer> getPrimeFactors(int upTo) {
List<Integer> result = new ArrayList<>();
for (int i = 2; i <= upTo; i++) {
if (upTo % i == 0) {
result.add(i);
}
}
return result;
}
And multiplying each of these numbers together to get all the combinations, and therefore find the closest.
I am trying to programme this so it is automated.
Any better solutions?

You don't need to calculate all factors, but you can go in both directions from the number to find its closest number which is the factor of given number
Pseduo code will be:
n= given number(dividend);
x= second number( whose closest number is required)
i=0;
if(n%x==0) print x;
else
while(true){
if(n%(x-i)==0){
print x-i
break
}
else if(n%(x+i)==0){
print x+i;
break
}
else i=i+1
}

I have my solution wrapped in a small static method:
/**
* #param target the number you want the factor to be close to
* #param number the number you want the result to be a factor of
*/
private static int getClosestFactor(int target, int number) {
for (int i = 0; i < number; i++) {
if (number % (target + i) == 0) {
return target + i;
} else if (number % (target - i) == 0) {
return target - i;
}
}
return number;
}

package dummy;
public class test {
public static void main(String[] args) {
int factorOff = 700;
int factorFrom = 30;
for (int i = 2; i < factorOff; i++) {
if (factorOff % (factorFrom + i) == 0) {
System.out.println(factorFrom + i);
i = factorOff;
} else if (factorFrom - i > 1 && factorOff % (factorFrom - i) == 0) {
System.out.println(factorFrom - i);
i = factorOff;
}
}
}
}

This should be a fast solution:
public static int findClosestFactor(int number, int closeTo) {
int result = 1;
int currentDist = closeTo - 1;
// stop conditions for comparison
boolean compareSmallFactor = true;
boolean compareLargeFactor = true;
for (int factor1 = (int) Math.sqrt(number); factor1 > 0; factor1--) {
if (number % factor1 == 0) {
if (compareSmallFactor) {
int dist1 = Math.abs(closeTo - factor1);
if (dist1 < currentDist) {
result = factor1;
currentDist = dist1;
}
// factor 1 is getting always smaller
// so you need not compare next time, if go away from target (smaller than target)
if (factor1 <= closeTo) {
compareSmallFactor = false;
}
}
if (compareLargeFactor) {
int factor2 = number / factor1;
int dist2 = Math.abs(closeTo - factor2);
if (dist2 < currentDist) {
result = factor2;
currentDist = dist2;
}
// factor 2 is getting always larger
// so you need not compare next time, if go away from target (larger than target)
if (factor2 >= closeTo) {
compareLargeFactor = false;
}
}
// if both factors go away from target, you can cancel
if (!compareSmallFactor && !compareLargeFactor) {
break;
}
}
}
return result;
}

You can factorize the number, then use a powerset generator (for a multiset[1]) to search for the group of factors that get closest to the max without going over.
The powerset generator can be modified to prevent further iteration down branches that exceed the desired value (branch and bound). IE: if factors are (2,5,7,13,19). The number is 80, and you have 2*5*7 = 70. 2 * 5 * 7 * 13 = 910. There is no need to check 2 * 5 * 7 * 19 as it would clearly exceed the max.
[1] It's a good idea to treat the factorization as an multiset. For example in the case of 700, ((2,2),(5,2),(7,1)). You could treat it as (2,2,5,5,7), but it would do extra work since there's no need to find 2 * 5 = 10 more than once, but if it's not treated as a multiset, then that would happen.

Related

Java: fast way to check if digits in int are in ascending order

I'm writing a program that finds all of the Armstrong numbers in a range between zero and Integer.MAX_VALUE. Time limit is 10 seconds. I've found that the most time-consuming method is the one that narrows the range of numbers to process by picking only those having their digits in ascending order (with trailing zeros if any). It takes about 57 seconds to run on my machine. Is there any way to make it faster?
static boolean isOK(int x)
{
int prev = 0;
while(x > 0)
{
int digit = x % 10;
if((digit > prev || digit == 0) && prev != 0) return false;
x /= 10;
prev = digit;
}
return true;
}
This method reduces the number of numbers to process from 2.147.483.647 to 140.990.
Perhaps instead of sifting through all the ints, just build up the set of numbers with digits in ascending order. I would argue that you probably want a set of strings (and not ints) because it it is easier to build (recursively by appending/ prepending characters) and then later on you need only the individual "digits" for the power test.
My take on the problem, goes to Long.MAX_VALUE (19 digits) in about 6 seconds and all the way to 39 digits in about an hour
One alternative is to construct the set of Armstrong numbers one by one and count them instead of checking every number to see whether it's an Armstrong number or not.
In constructing the whole set, note that when you choose each digit, the set of digits you can choose for the next position is determined, and so on. Two alternatives to implement such a method are recursion and backtracking (which is basically a cheaper way to implement recursion).
This method will not need the use of time-consuming division and remainder operations.
There is very little optimisable code here. It is likely that your time issue is elsewhere. However, one technique comes to mind and that is Memoization.
static Set<Integer> oks = new HashSet<>();
static boolean isOK(int x) {
if (!oks.contains(x)) {
int prev = 0;
while (x > 0) {
int digit = x % 10;
if ((digit > prev || digit == 0) && prev != 0) {
return false;
}
x /= 10;
prev = digit;
}
// This one is OK.
oks.add(x);
}
return true;
}
This trick uses a Set to remember all of the ok numbers so you don't need to check them. You could also keep a Set of those that failed too to avoid checking them again but keeping all integers in a collection is likely to break something.
You perform two divisions. Divisions are slower than multiplications. So is there a way to change a division into a multiplication? Well... yes, there is.
public static boolean isArmstrongNumber(int n) {
int prev = 0;
while (n > 0) {
int quotient = n / 10;
int digit = n - (quotient * 10);
if ((digit > prev || digit == 0) && prev != 0) {
return false;
}
n = quotient;
prev = digit;
}
return true;
}
The following code doesn't deal with trailing zeroes but is worth checking if it looks promising in terms of performance.
static boolean isOK(int x) {
if (x < 10) {
return true;
}
String xs = Integer.toString(x);
for (int i = 1; i < xs.length(); i++) {
if (xs.charAt(i) < xs.charAt(i - 1)) {
return false;
}
}
return true;
}
The following code runs x4 as fast as the original (3 sec. on my laptop) and prints 140990 in 3 sec.
The method isOK is unchanged
public class Main {
public static boolean isOK(int x) {
int prev = 0;
while (x > 0) {
int digit = x % 10;
if (prev != 0 && (digit > prev || digit == 0)) return false;
x /= 10;
prev = digit;
}
return true;
}
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
Set<Integer> candidates = IntStream.range(0, Integer.MAX_VALUE)
.parallel()
.filter(n -> isOK(n))
.boxed()
.collect(Collectors.toSet());
long stop = System.currentTimeMillis() - start;
System.err.printf("%d in %d sec.", candidates.size(), stop / 1000);
}
}
It has been asked on the MIU test, unfortunately, I was not able to solve it, I later worked on it and it worked fine.
static int isAscending(int n){
int rem, rem1, pval = 0; boolean isAsc = true;
while(n != 0){
rem = n % 10;
n /= 10;
rem1 = n % 10;
n /= 10;
if(rem > rem1){
continue;
} else {
isAsc = false;
break;
}
}
if(isAsc == true){
return 1;
} else {
return 0;
}
}

All digits in int are divisible by certain int

I am trying to figure out how to count all numbers between two ints(a and b), where all of the digits are divisible with another int(k) and 0 counts as divisible.Here is what I've made so far, but it is looping forever.
for (int i = a; i<=b; i++){
while (i < 10) {
digit = i % 10;
if(digit % k == 0 || digit == 0){
count ++;
}
i = i / 10;
}
}
Also I was thinking about comparing if all of the digits were divisible by counting them and comparing with number of digits int length = (int)Math.Log10(Math.Abs(number)) + 1;
Any help would be appreciated. Thank you!
Once you get in to your while block you're never going to get out of it. The while condition is when i less than 10. You're dividing i by 10 at the end of the whole block. i will never have a chance of getting above 10.
Try this one
public class Calculator {
public static void main(String[] args) {
int a = 2;
int b = 150;
int k = 3;
int count = 0;
for (int i = a; i <= b; i++) {
boolean isDivisible = true;
int num = i;
while (num != 0) {
int digit = num % 10;
if (digit % k != 0) {
isDivisible = false;
break;
}
num /= 10;
}
if (isDivisible) {
count++;
System.out.println(i+" is one such number.");
}
}
System.out.println("Total " + count + " numbers are divisible by " + k);
}
}
Ok, so there are quite a few things going on here, so we'll take this a piece at a time.
for (int i = a; i <= b; i++){
// This line is part of the biggest problem. This will cause the
// loop to skip entirely when you start with a >= 10. I'm assuming
// this is not the case, as you are seeing an infinite loop - which
// will happen when a < 10, for reasons I'll show below.
while (i < 10) {
digit = i % 10;
if(digit % k == 0 || digit == 0){
count ++;
// A missing line here will cause you to get incorrect
// results. You don't terminate the loop, so what you are
// actually counting is every digit that is divisible by k
// in every number between a and b.
}
// This is the other part of the biggest problem. This line
// causes the infinite loop because you are modifying the
// variable you are using as the loop counter. Mutable state is
// tricky like that.
i = i / 10;
}
}
It's possible to re-write this with minimal changes, but there are some improvements you can make that will provide a more readable result. This code is untested, but does compile, and should get you most of the way there.
// Extracting this out into a function is often a good idea.
private int countOfNumbersWithAllDigitsDivisibleByN(final int modBy, final int start, final int end) {
int count = 0;
// I prefer += to ++, as each statement should do only one thing,
// it's easier to reason about
for (int i = start; i <= end; i += 1) {
// Pulling this into a separate function prevents leaking
// state, which was the bulk of the issue in the original.
// Ternary if adds 1 or 0, depending on the result of the
// method call. When the methods are named sensibly, I find
// this can be more readable than a regular if construct.
count += ifAllDigitsDivisibleByN(modBy, i) ? 1 : 0;
}
return count;
}
private boolean ifAllDigitsDivisibleByN(final int modBy, final int i) {
// For smaller numbers, this won't make much of a difference, but
// in principle, there's no real reason to check every instance of
// a particular digit.
for(Integer digit : uniqueDigitsInN(i)) {
if ( !isDigitDivisibleBy(modBy, digit) ) {
return false;
}
}
return true;
}
// The switch to Integer is to avoid Java's auto-boxing, which
// can get expensive inside of a tight loop.
private boolean isDigitDivisibleBy(final Integer modBy, final Integer digit) {
// Always include parens to group sub-expressions, forgetting the
// precedence rules between && and || is a good way to introduce
// bugs.
return digit == 0 || (digit % modBy == 0);
}
private Set<Integer> uniqueDigitsInN(final int number) {
// Sets are an easy and efficient way to cull duplicates.
Set<Integer> digitsInN = new HashSet<>();
for (int n = number; n != 0; n /= 10) {
digitsInN.add(n % 10);
}
return digitsInN;
}

TestDome: my solution works but I am only getting %50 right and not %100?

This is the scenario question:
A frog only moves forward, but it can move in steps 1 inch long or in jumps 2 inches long. A frog can cover the same distance using different combinations of steps and jumps.
Write a function that calculates the number of different combinations a frog can use to cover a given distance.
For example, a distance of 3 inches can be covered in three ways: step-step-step, step-jump, and jump-step.
public class Frog{
public static int numberOfWays(int input) {
int counter = 2;
int x = 0;
for (int i = 1 ; i< input -1; i++ ){
x = i + counter;
counter = x;
}
if (input <3){
x = input;
}
return x;
}
public static void main(String[] args) {
System.out.println(numberOfWays(10));
}
}
This solution only gives me %50 right not sure why its not %100 right, I tested it with other values and returns the right results.
I think recursion is a nice way to solve problems like that
public int numberOfCombinations(int distance) {
if (distance == 1) {
return 1; //step
} else if (distance == 2) {
return 2; // (step + step) or jump
} else {
return numberOfCombinations(distance - 1) + numberOfCombinations(distance - 2);
// we jumped or stepped into the current field
}
}
Let f[n] be the number of combinations of steps and jumps such that you travel n inches. You can immediately see that f[n] = f[n-1] + f[n-2], that is first you can travel n-1 inches in some way and then use 1 step or you can travel n-2 inches in some way and then use 1 jump. Since f[1] = 1 and f[2] = 2 you can see that f[n] = fib(n+1), the n+1-th Fibonacci number. You can calculate it in linear time if it suits the purpose or, more efficiently, you can calculate it in log n time - reference
The problem is a modified version of the Fibonacci series. I get 100% for the following (sorry it's C# but is very similar):
using System;
public class Frog
{
public static int NumberOfWays(int n)
{
int firstnumber = 0, secondnumber = 1, result = 0;
if (n == 1) return 1;
if (n == 2) return 2;
for (int i = 2; i <= n + 1; i++)
{
result = firstnumber + secondnumber;
firstnumber = secondnumber;
secondnumber = result;
}
return result;
}
public static void Main(String[] args)
{
Console.WriteLine(NumberOfWays(3));
Console.WriteLine(NumberOfWays(4));
Console.WriteLine(NumberOfWays(5));
Console.WriteLine(NumberOfWays(6));
Console.WriteLine(NumberOfWays(7));
Console.WriteLine(NumberOfWays(8));
}
}
Think overlapping subproblem / dynamic programming. You need to memorize the repetitive calls to the sub-problem which will save you all the time.
I believe this should cover your all scenarios.
public static string numberOfCombinations(int distance)
{
if (distance == 1) {
return "Step";//1
} else if (distance == 2) {
return "Jump";//2
} else{
return numberOfCombinations(1) + numberOfCombinations(distance - 1);
}
}

How to count possible combination for coin problem

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.

Making solution for Project Euler more efficient

Originally, I was having some issues getting this code to function, but after a little tweaking I got it debugged and ready to go.
I have gone through several revisions of this program. I started with integer values only to find that the number was too large to fit into an int. I then changed to BigIntegers, which proved to be a hassle, but workable. From there, I switched to longs (as should have done from the beginning) and cut the runtime of my code 8-fold (or more).
Here's the code as it is now:
long qNum = 600851475143L;
for (long i = qNum - 1L; i * i >= qNum; i -= 2L)
if (qNum % i == 0 && isPrime(i)) {
System.out.println("Solution:" + i); // for debugging
return i;
}
else
System.out.println(i);// for debugging
return 0L;
And
public static boolean isPrime(long num) {
// unnecessary if statement for this problem (b/c of for loop), but useful for others
if (num % 2 == 0)
return false;
for (long i = 3; i * i <= num; i += 2)
if (num % i == 0)
return false;
return true;
}
It's been running for multiple hours and it still hasn't found anything. I saw online that solving this puzzle the typical way is like parsing 560GB of data =/.
Any tips for speeding this up?
Many thanks,
Justian
EDIT:
Optimized code:
public static long greatestPrimeFactor(ArrayList<Long> factors, long num) {
for (long i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
factors.add(i);
return greatestPrimeFactor(factors, num / i);
}
}
for (int i = factors.size()-1; i > 0; i--)
if (isPrime(factors.get(i)))
return num;
return 0;
}
AND
public static boolean isPrime(long num) {
if (num % 2 == 0)
return false;
for (long i = 3; i * i <= num; i += 2)
if (num % i == 0)
return false;
return true;
}
RUN WITH
greatestPrimeFactor(new ArrayList<Long>(), 600851475143L);
My solution hits in less than a hundredth of a second. Each time you find a divisor of the number, divide the number by that divisor and start again. The highest number you divide by is your target.
You are doing too many unnecessary things. Here's a simpler solution:
long greatestFactor(long n) {
long p = 0;
for (long k = 2; k * k <= n; k++)
while (n % k == 0) {
n /= k;
p = k;
}
if (n > 1)
p = n;
return p;
}
You don't need to test every number for whether or not it is prime. You see this, so you only test every ODD number (well, and 2). You can take this further! Construct a table of the first few million primes quickly, and only test against those. You'll go a LOT faster, with a very small overhead.
Edit: Here's what I was talking about. It's quite straightforward. Notice how I only compare the values to already computed primes. Once you've computed a fair number of them (say, the first 10000000 primes) start doing your search based on on the +2 method like you are. Keep in mind that most of them are going to get caught early because you're skipping unnecessary numbers. You don't need to test 15,25,35,45,55, etc, because you already tested 5. That in and of itself is going to cull about 20% of your tests, which easily accounts for the overhead of calculating the first few million numbers.
Sample output
C:\files\j\misc>java sandbox2
resized to 200
resized to 400
resized to 800
resized to 1600
resized to 3200
resized to 6400
resized to 12800
resized to 25600
resized to 51200
resized to 102400
resized to 204800
resized to 409600
resized to 819200
664579 primes in 18 seconds. Last prime was 9999991
C:\files\j\misc>
Sample code:
public class sandbox2 {
static int[] primes = new int[100]; // where the primes really are
static int count = 0;
static long mostRecentPrime;
public static void main(String[] args) throws Exception {
addPrime(2); // give it a couple to start
addPrime(3);
addPrime(5);
long start = System.currentTimeMillis();
for(long i = 7; i < 10000000; i++) { // all primes less than 10M
if(isPrime(i)) addPrime(i);
}
long end = System.currentTimeMillis();
long time = (end-start) / 1000;
System.out.println(count + " primes in " + time + " seconds. Last prime was " + mostRecentPrime);
}
public static boolean isPrime(long i) {
long max = (long)(Math.sqrt(i))+1;
for(int pos = 0; primes[pos] < max && pos < primes.length; pos++) {
long prime = (long)(primes[pos]);
if(i % prime == 0) return false;
}
return true;
}
public static void addPrime(long p) {
mostRecentPrime = p;
if(count == primes.length) { // resize if necessary
int size = primes.length * 2;
int[] newprimes = new int[size];
System.arraycopy(primes, 0, newprimes, 0, primes.length);
primes = newprimes;
System.out.println("resized to " + primes.length);
}
primes[(int)count] = (int)p;
count++;
}
}
In python, you can just calculate all the prime factors and then use the max function, like so:
def calc_prime_factors(n,i=2,result=[]):
while i<=n:
while n%i!=0:
i+=1
result.append(i)
if n!=1:
n,i=n/i,2
else:
break
return result
print max(calc_prime_factors(600851475143))

Categories

Resources